jvm中内存划分:
如上图,一共分为五块,其中:
线程共享区域为:
1、java堆
2、方法区
线程私有区域为:
3、JVM栈
4、本地方法栈
5、程序计数器
java技术体系中锁提倡的自动内存管理归结为自动化的解决了两个问题:
(1)给对象分配内存
(2)回收给对象分配的内存(关于回收算法请另见 http://www.cnblogs.com/Booker808-java/p/9063677.html)
对象的内存分配,往大了讲就是在堆上面进行分配,对象主要是分配在新生代的Eden区域,当然因为分配内存时的并发问题,我们会创建 TLAB(ThreadLocalAllocationBuffer),这个是指本地线程分配缓存。当然少数情况下,JVM也会将对象分配在老年代,分配规则不是固定的,而是根据不同的垃圾收集器组合而决定的!!
对象优先分配在Eden区
大多数情况下,对象会优先分配在Eden区,如果eden区域没有足够的空间的话,系统会发生一次Minor GC,这个gc会对目前eden区域里的对象进行判断,把当前eden区域里的对象放入到survivor区,如果survivor区域空间也不够的话(当然,大部分情况下survivor区域要远小于eden区),就会根据分配担保机制而把对象转到老年代。
大对象直接进入老年代
大对象是指,需要一大块连续内存空间的java对象,典型的就是字符串和数组。大对象的分配对虚拟机就是一个坏消息(当然,最坏的还是那种“短命大对象”),如果要分配很多大对象,经常会发生为了分配这些对象而提前发生gc。
虚拟机提供了一个参数,大于该参数内存的对象直接进入老年代。这样做的好处是,可以避免eden区和俩survivor区之间发生太多的内存复制的操作而浪费性能(因为新生代对象的gc采用的大多是复制算法)
长期存活的对象将进入老年代
既然虚拟机选择采用分代收集的思想来管理内存,那么在内存回收时应该注意,哪些对象应该放在新生代和老年代。为此,虚拟机为每个对象都定义了一个年龄计数器,如果一个对象在进行了Minor Gc后,还能存活,并且能被survivor区容纳的话,就会被移动到survivor区,并且计数器加1,当年龄达到一定数量时,就会进入到老年代。
空间分配担保
在发生minor Gc时,虚拟机会首先检查一下老年代的最大可用空间是否大于新生代所有空间,如果成立,那么这次的minor gc就是安全的,否则,虚拟机会看用户设置的一个参数,该参数决定是否允许担保失败,如果允许,虚拟机就会继续检查老年代最大可用空间是否大于历代晋升到老年代对象的平均大小,如果大于,会尝试着minor gc,如果小于平均值,这次就要对老年代进行full gc,full gc就是把老年代里不常用的对象进行回收。
取平均值的做法比较取巧,就算大于历代平均值,也可能会发生担保失败,所以大多数情况下都不会去设置允许担保失败,因为可以避免full gc过于频繁,也能提高系统的性能!