java内存管理机制_Java内存管理机制

JVM内存管理机制说到底就是为了解决两个问题:给对象分配内存以及回收分配给对象的内存。

Java Heap被分为两部分:Young Generation 和 Old Gereration。Perm并不属于Heap。

91becf1da6739ee5ddd036226a850e8b.png

Young Generation (Young Gen)

所有的new出来的对象都放在Young Gen,当Young Gen满了, 就会执行Garbage Collection (GC), 此时的GC称为Minor GC。 Young Gen被分成三部分:Eden Memory和两个Survivor Memory。

多数情况下,对象都在新生代Eden区中分配,但一些大对象可能会直接进入到老年代。虚拟机提供了一个 -XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接进老年代分配,这样做的目的是避免在Eden区以及两个Survivor区之间发生大量的内存拷贝。

Eden满了怎么办?JVM就会执行Minor GC。被引用的对象都会存活下来,它们将被移到Survivor区域里,也就是 图中的S0或S1。

同一时间的两个Survivor区,一个用来保存对象,另一个是空的;每次进行Minor GC垃圾回收时,就把Eden,From的可达对象复制到To区域中,一些生存时间长的就复制到老年代,接着就清除Eden,From空间,最后把原来的To空间变为From空间,原来的From空间变为To空间。( 有点类似于双缓冲队列 )

虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并进过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并将对象年龄设为1。对象在Survivro区中每熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁)时,就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold来设置。

动态对象年龄判定:为了能更好地适应不同程序的内存状况,虚拟机并不总是要求对象的年龄必须达到MaxTenuringThreshold才能晋升到老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。

Young区域大部分对象 朝生夕灭,因此Minor GC回收频率高且回收速度很快。

新生代采用 复制算法 。

Old Generation(Tenured Gen)

回收机制:采用标记压缩算法回收垃圾。

对象来源:

大对象直接进入老年代

Young代中生存时间长的可达对象。

回收频率:因为很少对象会死掉,所以执行频率不高,而且需要较长时间来完成。

Permanent Generation(永久代)

绝大部分 Java 程序员应该都见过 "java.lang.OutOfMemoryError: PermGen space "这个异常。这里的 “PermGen space”其实指的就是方法区。不过方法区和“PermGen space”又有着本质的区别。前者是 JVM 的规范,而后者则是 JVM 规范的一种实现,并且只有 HotSpot 才有 “PermGen space”,而对于其他类型的虚拟机,如 JRockit(Oracle)、J9(IBM) 并没有“PermGen space”。由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出。我们现在通过动态生成类来模拟 “PermGen space”的内存溢出:

import java.io.File;

import java.net.URL;

import java.net.URLClassLoader;

import java.util.ArrayList;

import java.util.List;

public class PermGenOomMock{

public static void main(String[] args) {

URL url = null;

List classLoaderList = new ArrayList<>();

try {

url = new File("/tmp").toURI().toURL();

URL[] urls = {url};

while (true){

ClassLoader loader = new URLClassLoader(urls);

classLoaderList.add(loader);

loader.loadClass("java.lang.Object");

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

at java.util.concurrent.locks.ReentrantLock.(ReentrantLock.java:262)

at java.util.concurrent.ConcurrentHashMap$Segment.(ConcurrentHashMap.java:425)

at java.util.concurrent.ConcurrentHashMap.(ConcurrentHashMap.java:825)

at java.util.concurrent.ConcurrentHashMap.(ConcurrentHashMap.java:869)

at java.lang.ClassLoader.(ClassLoader.java:281)

at java.lang.ClassLoader.(ClassLoader.java:334)

at java.security.SecureClassLoader.(SecureClassLoader.java:99)

at java.net.URLClassLoader.(URLClassLoader.java:140)

at com.boothsun.jvm.PermGenOomMock.main(PermGenOomMock.java:17)

本例中使用的 JDK 版本是 1.7,指定的 PermGen 区的大小为 8M。通过每次生成不同URLClassLoader对象来加载Test类,从而生成不同的类对象,这样就能看到我们熟悉的 "java.lang.OutOfMemoryError: PermGen space " 异常了。这里之所以采用 JDK 1.7,是因为在 JDK 1.8 中, HotSpot 已经没有 “PermGen space”这个区间了,取而代之是一个叫做 Metaspace(元空间) 的东西。下面我们就来看看 Metaspace 与 PermGen space 的区别。

MetaSpace(元空间)

JDK1.8 永久代的废弃

JDK1.8 永久代变化如下图:

d93bbc1ed60b2b689821c75c2a9e297a.png

新生代:Eden + From Survivor + To Survivor

老年代:OldGen

永久代(方法区的实现):PermGen ---> 替换为Metaspace(本地内存中)

移除永久代的原因

移除永久代是为融合HotSpot JVM与JRockit VM而做出的努力,因为JRockit没有永久代,不需要配置永久代。

永久代大小不确定,PermSize指定的太小很容易造成永久代OOM,因为PermSize的大小很依赖于很多因素,比如JVM加载的class总数,常量池的大小,方法的大小等。

元空间的内存大小

元空间时方法区的具体实现,方法区主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常称为“非堆”。

元空间的本地和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。 理论上取决于32位/64位系统可虚拟的内存大小。可见也不是无限制的,需要配置参数。

常用配置参数

MetaspaceSize

初始化的Metaspace大小,控制元空间发生GC的阈值。GC后,动态增加或降低MetaspaceSize。在默认情况下,这个值大小根据不同的平台在12M到20M浮动。

MaxMetaspaceSize

限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存,影响到其他程序。在本机上该参数的默认值为4294967295B(大约4096MB)。

MinMetaspaceFreeRatio

当进行过Metaspace GC之后,会计算当前Metaspace的空闲空间比,如果空闲比小于这个参数(即实际非空闲占比过大,内存不够用),那么虚拟机将增长Metaspace的大小。默认值为40,也就是40%。设置该参数可以控制Metaspace的增长的速度,太小的值会导致Metaspace增长的缓慢,Metaspace的使用逐渐趋于饱和,可能会影响之后类的加载。而太大的值会导致Metaspace增长的过快,浪费内存。

MaxMetasaceFreeRatio

当进行过Metaspace GC之后, 会计算当前Metaspace的空闲空间比,如果空闲比大于这个参数,那么虚拟机会释放Metaspace的部分空间。默认值为70,也就是70%。

MaxMetaspaceExpansion

Metaspace增长时的最大幅度。在本机上该参数的默认值为5452592B(大约为5MB)。

MinMetaspaceExpansion

Metaspace增长时的最小幅度。在本机上该参数的默认值为340784B(大约330KB为)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值