根据虚拟机规范,JVM的内存分为 堆、虚拟机栈、本地方法栈、程序计数器、方法区。
JDK 1.8 同 JDK 1.7 比,最大的差别就是: 元数据区取代了永久代 。元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现。不过元空间与永久代之间最大的区别在于: 元数据空间并不在虚拟机中,而是使用本地内存。
虚拟机的内存中主要有 程序计数器、虚拟机栈、本地方法栈、堆和方法区。
引用计数法 : 一个对象被其它变量所引用,计数+1。如果某一个变量不再引用它了,计数-1。 当计数为0时可以被回收。
存在问题:如果发生循环引用,如下图。A、B两个对象都不会被回收,计数都为1。
可达性分析算法 :首先会确定一系列的根对象(GC Root), 按照从上至下的方式搜索被根对象集 合所连接的目标对象是否可达,如果该对象被跟对象直接或间接的引用,就 不能被回收,否则就会被回收。 该算法可以有效地解决在引用计数算法中循 环引用的问题,防止内存泄漏的发生。
虚拟机栈中引用的对象:各个线程被调用的方法中使用到的参数、局部变量等。
方法区中类静态属性引用的对象 比如:Java类的引用类型静态变量
方法区中常量引用的对象比如:字符串常量池(string Table)里的引用
优点:速度快
缺点: 内存碎片化严重 ,后续可能发生大对象不能找到可利用空间的问题, 会造成内存溢出。
标记后不是清理对象,而是 将存活对象移向内存的一端 。然后清除端边界外的对象。
优点:没有内存碎片
缺点:速度慢、内存开销大
按内存容量将内存划分为等大小的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉。
优点:速度快、不会有内存碎片
缺点:占用双倍空间
强引用:强引用j就是我们常见的普通引用对象,我们程序中几乎所有的引用使用的都是强引 用。只要还有一个强引用指向一个对象,就表明该对象还活着,不能被回收
软引用:一个软引用中的对象,不会很快被JVM回收,当JVM内存不足时,才会对其进行回收
弱引用:比软引用拥有更短的生命周期。在垃圾回收时,只要发现弱引用,不管堆空间是否 足够,都会将对象进行回收。由于垃圾回收器是一个 优先级很低的线程 ,因此 不一定 会 很快 发现那些只具有 弱引用 的对象。
虚引用: 虚引用 就是 形同虚设 它并不能决定 对象的生命周期。任何时候这个只有虚引用的对 象都有可能被回收。因此,虚引用主要用来跟踪对象的回收,清理被销毁对象的相关 资源。
StackOverFlowError
解释:线程栈内存溢出,
原因:方法递归调用
OutOfMemoryError:Java heap memory
解释:堆内存溢出
原因:大量对象创建撑爆堆区
OutOfMemoryError:Metaspace
解释:方法区溢出
原因:大量类被加载
Java 的自动 内存管理 主要是针对 对象内存的回收 和 对象内存的分配 。同时,Java 自动内存管理最核心的功能是 堆 内存中对象的分配与回收。
堆中存放我们new出来的对象,存放的区域就是Eden区域,但这个区域存满以后就会做minor gc, 首先通过可达性分析算法来判断是否是垃圾, 如果能够找到引用就不是垃圾,找不到就是垃圾,minor gc过程中我们有一部分是垃圾一部分不是垃圾,会将这些垃圾对象清除,然后 非垃圾对象会放到survivor区域的to中 , 并且将对象的分代年龄+1 ,分代年龄(用来区分对象生命周期的一种标识,比如parallel默认 对象分代年龄达到15岁就放到老年代中 )。此时一次minor gc结束。我们可以推断出, 老年代做full gc的频率应该远远小于年轻代minor gc ,老年代等到存放对象快满的时候会做full gc,扫描老年代中的对象是否是垃圾,如果都不是并且此时还有对象要进入老年代,那此时就会报OOM(内存溢出错误)。
新生代使用的复制算法,老年代使用的是标记整理算法。
指的是GC事件发生过程中, 会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应, 有点像卡死的感觉 ,这个停顿称为STW。可达性分析算法中枚举根节点(GC Roots)会导致所有Java执行线程停顿。
原因很简单,因为java进行垃圾回收时使用可达性分析,从GC Root向下判断对象是否有引用,如果不把所有线程进入safe points并阻塞起来就会出现对象上一秒没有引用被删除,后一秒又出现引用,导致错误的产生。
| 留言与评论(共有 0 条评论) “” |