对象创建与堆
这一节主要介绍对象创建时,在堆中的一些过程。
回忆下,我们之前说的,什么时候会发生垃圾回收?
除了在一些安全点处也许会发生垃圾回收(只是也许),如果在所需内存不足的情况下,一定会发生垃圾回收。
分配堆空间
首先通过设置参数,把堆空间设置为 20M,其中 新生代 10M,老年代 10M。
参数设置:
-Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails
结果为:
Heap PSYoungGen total 9216K, used 1685K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000) eden space 8192K, 20% used [0x00000007bf600000,0x00000007bf7a5580,0x00000007bfe00000) from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000) to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000) ParOldGen total 10240K, used 0K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000) object space 10240K, 0% used [0x00000007bec00000,0x00000007bec00000,0x00000007bf600000)
创建一个新对象
我们首先创建一个对象,这个对象占用 2M 的空间。
package heap; public class CreateObject { public static void main(String[] args) { byte[] obj1 = new byte[1024 * 1024 * 2]; } }
最后的输出:
Heap PSYoungGen total 9216K, used 3733K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000) eden space 8192K, 45% used [0x00000007bf600000,0x00000007bf9a5590,0x00000007bfe00000) from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000) to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000) ParOldGen total 10240K, used 0K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000) object space 10240K, 0% used [0x00000007bec00000,0x00000007bec00000,0x00000007bf600000)
可以看到,新生代 被占用了,老年代占用为 0K,没有被使用。
所以,new 的对象先放在 eden 区。
填满 eden 区
在填满 eden 区后,会发生什么呢?因为 survivor 区实在太小了,很难看到。所以,这里可以借助 Visual VM,来观察,更加直观。
程序如下:
package heap; public class CreateObject { public static void main(String[] args) { while(true){ byte[] bytes = new byte[1024 * 512]; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
重点是看右边的记录图。注意,这里我们将每次创建对象的大小设置为了 0.5M。
当 Eden 满的时候,会调用垃圾回收器,调用垃圾回收器后,Eden 出现了低谷,Survivor 出现了一个增长。老年区也出现了一个增长。
当 Eden 满的时候,如果 Survivor 区有足够的空间容纳存活对象,那么可以把存活对象放入 Survivor,多的对象放入老年区。
现在,我们把对象的大小调大。设置为 2M,这样 Survivor 就无法存放下。
可以看到,在经过一次垃圾回收的时候(可以看到GC Time 上有波峰,说明执行了一次垃圾回收),但我们注意到,Survivor 区中并没有被占用。说明垃圾回收过程中,直接将存活对象放到了老年代中。
再来聊聊 survivor 区
对象通常在 Eden 区里诞生,如果经过第一次 MInor GC 后仍然存活,并且能够被 Survivor 容纳的话,该对象会被移动到 Survivor 区,并且将其年龄设置为 1 岁。对象在 Survivor 区每熬过一次 Minor GC,年龄就增加 1 岁,当它年龄增大到一定程度(默认是 15 岁),就会被晋升到老年代。
特殊情况
有些时候,如果用户创建了大对象,如很长的字符串或者元素很多的数组的时候。这种大对象都占用大量的内存,像这种大对象,有很大概率是长时间使用的,不然为什么要创建大对象。
如果大对象朝生夕灭,我们知道在 Java 8 中,新生代默认采用的 标记-复制 算法,那么对于大对象而言,是非常耗时的。
所以,如果 JVM 设置了一个阈值,那么当分配的对象大于这个阈值的时候,会直接被分配到老年代。
总结
- js创建对象 之 工厂模式,构造函数模式
- javascript创建对象的四种方法
- JavaScript学习笔记,创建对象,属性访问
- 创建java对象的方法
- SharePoint 服务器端对象模型操作用户组(创建/添加/删除)
- wps二次开发无法创建对象wps.application的解决方案
- JavaScript 创建对象基础语法
- js创建对象的几种方式
- 21天学通JAVA:类的定义和对象的创建
- js6种创建类/对象的方法
- java创建JSONObjecty以及JSONArray,java对象与json对象互转
- iOS 创建对象的姿势
- JavaScript构造函数创建对象
- 以支持多种浏览器的方式创建 XMLHttpRequest 对象
- JavaScript 创建对象实例 【每日一段代码77】
- javascript对象创建过程
- 复杂对象的组装与创建——建造者模式(二):建造者模式解决方案
- WCF初探-13:WCF客户端为双工服务创建回调对象
- spring之IOC容器创建对象
- 创建对象有哪些方法