Jvm堆内存管理

1.概念解释

1.1 年青代=新生代(eden space)+2个survivor

年青代用来存放新近创建的对象,尺寸随堆大小的增大和减小而相应的变化,默认值是保持为堆大小的1/15,可以通过-Xmn参数设置年青代为固定大小,也可以通过-XX:NewRatio来设置年青代与年老代的大小比例,年青代的特点是对象更新速度快,在短时间内产生大量的“死亡对象”。
年轻代的特点是产生大量的死亡对象,并且要是产生连续可用的空间, 所以使用复制清除算法和并行收集器进行垃圾回收.     对年轻代的垃圾回收称作初级回收 (minor gc)

初级回收将年轻代分为三个区域,  一个新生代 , 2个大小相同的复活代,  应用程序只能使用一个新生代和一个复活代, 当发生初级垃圾回收的时候,gc挂起程序, 然后将新生代和复活代中的存活对象复制到另外一个非活动的复活代中,然后一次性清除新生代和复活代,将原来的非复活代标记成为活动复活代.    将在指定次数回收后仍然存在的对象移动到年老代中, 初级回收后,得到一个空的可用的新生代.

1.2
所谓的新生代和老年代是针对于分代收集算法来定义的,新生代又分为Eden和Survivor两个区。加上老年代就这三个区。数据会首先分配到Eden区当中(当然也有特殊情况,如果是大对象那么会直接放入到老年代(大对象是指需要大量连续内存空间的java对象)。),当Eden没有足够空间的时候就会触发jvm发起一次Minor GC。如果对象经过一次Minor GC还存活,并且又能被Survivor空间接受,那么将被移动到Survivor空间当中。并将其年龄设为1,对象在Survivor每熬过一次Minor GC,年龄就加1,当年龄达到一定的程度(默认为15)时,就会被晋升到老年代中了,当然晋升老年代的年龄是可以设置的。
其实新生代和老年代就是针对于对象做分区存储,更便于回收等等。

2.相关的启动参数:年轻代、老年代和永久代的内存分配

如果想观察JVM进程占用的堆内存,可以通过命令工具jmap或者可视化工具jvisualvm.exe。JVM这些启动参数都拥有默认值,如果想了解JVM的内存分配策略,最好手动设置这些启动参数。再通过JDK提供的工具的统计结果,进行对比,就比较容易理解这些内存分配的理论知识。运行环境是win7 32位操作系统,JDK1.7.0_60版本。

测试代码和JVM启动参数如下:

1
2
3
4
5
6
7
8
9
10
11
public class Test
{
     public static void main(String[] args)
     {
         int a = 0 ;
         while ( true )
         {
             a++;
         }
     }
}
1
2
-Xms=200M  -Xmx200M -XX:NewSize=100M -Xmn100M -XX:SurvivorRatio= 8
-XX:OldSize=60M -XX:PermSize=50M -XX:MaxPermSize=50M

运行上述代码,通过jps命令获取到进程pid,然后通过jmap -heap pid就可以查看内存分配和使用情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>jmap -heap 8912
Attaching to process ID 8912 , please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 24.60 -b09
 
using thread-local object allocation.
Mark Sweep Compact GC
 
Heap Configuration:
    MinHeapFreeRatio = 40
    MaxHeapFreeRatio = 70
    MaxHeapSize      = 209715200 ( 200 .0MB)
    NewSize          = 104857600 ( 100 .0MB)
    MaxNewSize       = 104857600 ( 100 .0MB)
    OldSize          = 62914560 ( 60 .0MB)
    NewRatio         = 3
    SurvivorRatio    = 8
    PermSize         = 52428800 ( 50 .0MB)
    MaxPermSize      = 52428800 ( 50 .0MB)

这里显示的堆配置参数,都可以通过JVM启动参数来设置。下面来解释下几个重要参数的含义:


-Xms 和 -Xmx (-XX:InitialHeapSize 和 -XX:MaxHeapSize):指定JVM初始占用的堆内存和最大堆内存。JVM也是一个软件,也必须要获取本机的物理内

存,然后JVM会负责管理向操作系统申请到的内存资源。JVM启动的时候会向操作系统申请 -Xms 设置的内存,JVM启动后运行一段时间,如果发现内存空间

不足,会再次向操作系统申请内存。JVM能够获取到的最大堆内存是-Xmx设置的值。


-XX:NewSize 和 -Xmn(-XX:MaxNewSize):指定JVM启动时分配的新生代内存和新生代最大内存。


-XX:SurvivorRatio:设置新生代中1个Eden区与1个Survivor区的大小比值。在hotspot虚拟机中,新生代 = 1个Eden + 2个Survivor。如果新生代内存是

10M,SurvivorRatio=8,那么Eden区占8M,2个Survivor区各占1M。


-XX:NewRatio:指定老年代/新生代的堆内存比例。在hotspot虚拟机中,堆内存 = 新生代 + 老年代。如果-XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆内存的1/5。在设置了-XX:MaxNewSize的情况下,-XX:NewRatio的值会被忽略,老年代的内存=堆内存 - 新生代内存。老年代的最大内存 = 堆内存 - 新生代 最大内存。


-XX:OldSize:设置JVM启动分配的老年代内存大小,类似于新生代内存的初始大小-XX:NewSize。


-XX:PermSize 和 -XX:MaxPermSize:指定JVM中的永久代(方法区)的大小。可以看到:永久代不属于堆内存,堆内存只包含新生代和老年代


可以发现:堆内存、新生代内存、老年代内存、永久代内存,都有一个初始内存,还有一个最大内存。下面以老年代的初始内存和最大内存为例,看下内存变化的效果,其他的应该类似。测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TurnedTest
{
     private static List<string> list = new ArrayList<string>();
 
     public static void main(String[] args)
     {
         int a = 0 ;
         while ( true )
         {
             a++;
 
             list.add( "demo" );
         }
 
     }
}</string></string>
显然这个程序存在内存泄露,最终会占满整个堆内存,抛出OOM。为了看清楚这个演变的过程,我们在while循环中添加一个断点,设置breakpoint properties中的"hit count"为100000,以debug模式运行上面的程序,然后使用jmap观察内存占用情况。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
tenured generation:
capacity = 62914560 ( 60 .0MB)
used     = 0 ( 0 .0MB)
free     = 62914560 ( 60 .0MB)
0.0 % used
 
 
tenured generation:
capacity = 62914560 ( 60 .0MB)
used     = 16409080 ( 15 .648918151855469MB)
free     = 46505480 ( 44 .35108184814453MB)
26.08153025309245 % used
 
tenured generation:
capacity = 62914560 ( 60 .0MB)
used     = 53329496 ( 50 .858970642089844MB)
free     = 9585064 ( 9 .141029357910156MB)
84.76495107014973 % used
 
tenured generation:
capacity = 104857600 ( 100 .0MB)
used     = 84217880 ( 80 .3164291381836MB)
free     = 20639720 ( 19 .683570861816406MB)
80.3164291381836 % used
可以发现老年代内存从最开始的60M,扩大到最大值100M。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值