说到 java 对象的创建, 首先应该提下 java 的内存机制, 最主要的两块应该就是堆内存和栈内存.
简单点来说栈内存主要是保存基本数据类型的值和保存引用变量, 堆内存主要用来存放 new 产生的对象, 数组.
堆是被所有线程共享的一块内存区域, 在虚拟机启动的时候被创建. 我的理解就是堆是用来存放实实在在东西的, 而栈只是用来存放一个编号的.
好比你是个真实存在的人 (编号 9527, 这个就是那些栈中引用指向的地方), 你就是放在堆中, 你的名字叫张三, 而这个张三是放在栈中一个引用变量, 你也可以有一个小名叫李二狗, 这个李二狗和张三都是指向堆中 9527 这个对象.
其次还有方法区. 方法区用来存放已被加载的类的信息, 常量, 静态变量. 常量池是在方法区中而不是堆内存中,"AAA" 字符串是在常量池的 ,new String("AAA"), 会在常量创建一个 "AAA" 字符串, 还会在堆中创建一个字符串对象.
对象的创建:
1. 避免创建不必要的对象, 避免在方法内部创建对象, 因为如果在方法内部创建对象 XX xxx = new XXX(); 不考虑线程安全的条件下如果有 N 个线程调用该方法, 那么就会创建 N 个 XXX 对象.
2. 考虑使用单例模式
3. 一些不需要改变的工具类可以使用 static 静态代码块来初始化. private static final XXX xxx;static {xxx = new XXX();}, 首先 static 修饰的字段是属于类的, 所有对象都可以使用, 其次静态代码块只会在类加载的时候初始化一次也就只会创建一个 XXX 对象.
4. 尽量使用基础数据类型, 避免使用包装类, 一是拆箱装箱耗时, 二是对象比基础数据更占内存. 可以试试: Long sum = 0L;for(int i = 0;i<Integer.MAX_VALUE;i++){sum += i;}, 将 sum 的生命改成基础数据类型 long 再试试.
对象的销毁: java 中如果一个栈先增长, 再收缩, 那么从栈中弹出来的对象不会被当作垃圾回收, 即使栈中已经不再引用这些对象. 因为栈中还维护对这些对象的过期引用 (永远也不会再被解除的引用)
1. 某些情况下, 可以考虑将某些引用置空告诉 jvm 这个对象已经没有引用了; 即使后面再有使用也会抛出空异常, 很快便可以发现问题.
2. 避免调用 finalizer 方法, 子类如果重写该方法清除一些资源, 切记在重写方法中还要手动调用父类的该方法 super.finalizer (); 而且最好是在 finally 中调用, 保证不管发生什么异常父类的 finalizer 方法都会执行
3. 可以考虑提供一些清理资源的方法. 比如 io 流相关类都提供 close 方法, 数据库连接 Connection 也有 close 关闭连接
来源: https://www.cnblogs.com/nijunyang/p/9069885.html