内存抖动是什么?怎么解决?内存溢出是什么?怎么解决?垃圾回收机制是什么样的?

学习目标:

内存泄漏与内存溢出 浅析

学习目标:

  1. JVM内存泄漏与内存溢出的区别?
  2. 内存抖动是什么?怎么解决?
  3. 垃圾回收机制是什么样的?

学习内容:

1.JVM内存泄漏与内存溢出的区别?
  • 内存泄漏
    程序在申请内存后,被某个对象一直持有,无法释放已经申请的内存空间,一次而内存泄漏危害不大,但是堆积起来就很严重了,无论多少内存,随着时间的推移,迟早都会用光。
  • 内存溢出
    程序在申请内存时,没有足够的内存空间供其使用,出现out of memory,Android系统为每个应用程序申请到的内存有限,一般为64M或者128M,我们也可以在AndroidMainfest中配置android:largeheap="true",从而给App申请更大的内存空间。
    图 1-1
    在这里插入图片描述
    这是一张经典的JVM虚拟机原理图,内存溢出一般发生在堆和虚拟栈中,而内存泄漏则发生在方法区,虚拟栈以及堆中。
    在这里插入图片描述
    在这里插入图片描述
2.内存抖动是什么?怎么解决?

内存抖动是指在短时间内有大量的对象被创建或被回收。怎么解决? 复用

3.垃圾回收机制是什么样的?

首先这里就可以先看一下上面的图1-1
然后通过代码的方式来讲解。

public class Fruit{
	static int x = 10;
	static BigWaterMelon bigWaterMelon_1 = new BigWaterMelon(10);
	int y = 20;
	BigWaterMelon bigWaterMelon_2 = new BigWaterMelon(y);
	public static void main(String[] args){
		Fruit fruit = new Fruit();
		int z = 30;
		final BigWaterMelon bigWaterMelon_3 = new BigWaterMelon(z);
		new Thread(new Runnable(){
			@Override
			public void run(){
				int k = 100;
				setWeight(k);
			}
		}).start();
		void setWeight(int waterMelonHeight){
			fruit.bigWaterMelon_2.weight = waterMelonHeight;
			bigWaterMelon_3.weight = waterMelonHeight;
		}
	}
}

class BigWaterMelon{
	private int weight;
	public BigWaterMelon(int weight){
		this.weight = weight;
	}
}

代码敲完,这里我就画了一张简易的图片,大致描述了一下上面的代码在虚拟机里的执行过程。
在这里插入图片描述

java垃圾回收算法中之前是引用计数器,意思就是给每个对象分配一个计算器,当有引用指向这个对象时,计数器加1,当指向该对象的引用失效时,计数器减1。最后如果该对象的计算器为0时,java垃圾回收器会认为该对象是可回收的。

  • 优点:

实时性
无需等到内存不够的时候,才开始回收,运行时根据对象的计数器是否为0,就可以直接回收。
应用无需挂起 在垃圾回收过程中,应用无需挂起。如果申请内存时,内存不足,则立刻报outofmember 错误。
区域性
更新对象的计数器时,只是影响到该对象,不会扫描全部对象

  • 缺点:

每次对象被引用时,都需要去更新计数器,有一点时间开销。另外无法解决循环引用问题。

所以就诞生了标记 - 清除

该算法有两个阶段。

  1. 标记阶段:找到所有可访问的对象,做个标记
  2. 清除阶段:遍历堆,把未被标记的对象回收
  • 缺点:

清理完过后会造成内存碎片过多,当存入大的对象时,无法找到足够的连续内存,而不得已会再次触发GC。

然后就诞生了标记 - 整理

首先需要标记出存活的对象,然后整理就是把存活的对象往一端推。然后就清除边界以外的区域即可。
这个算法就避免了碎片的问题。一般年轻代中执行GC后,会有少量的对象存活,就会用复制算法,只要付出少量的存活对象复制成本就可以完成收集,而老年代中因为对象存活率高,没有额外过多的内存空间分配,就需要标记-整理算法来进行回收。

而Android 的垃圾回收机制,就不一样了,因为Android手机的内存很宝贵,所以会有所变化。
在这里插入图片描述

每次创建对象都是在生存区,当伊甸园区(生成区)的空间用完时候,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC,也叫轻GC 或者是YGC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后伊甸园中的剩余对象移动到幸存0区(也叫FromSpace)。若幸存0区也满了,再对该地区进行垃圾回收,然后移动到1区(也叫ToSpace)。
如果1区也满了怎么办呢?在经历了15次YGC后,幸存1区也满了,那么这个时候,JVM将会把这些数据移动到养老区。如果养老区也满了,这个时候就会进行MajorGC(也称Full GC 检查FGC)。执行full GC对养老区的内存进行清理。如果养老区执行了Full GC之后,发现依然无法进行对象的保存,这个时候就会出现OOM(OutOfMemoryError)异常了。

那我们在什么条件下就可以判定对象可以回收了?
我们的new 出来的对象都会引用一个GC Root,通过这个来判定是否回收。
GC Root对象

通过可达性算法,成功解决了引用计数所无法解决的问题-“循环依赖”,只要你无法与 GC Root
建立直接或间接的连接,系统就会判定你为可回收对象。那这样就引申出了另一个问题,哪些属于 GC Root。 在 Java 语言中,可作为 GC
Root 的对象包括以下4种:

虚拟机栈(栈帧中的局部变量表)中引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象 本地方法栈中 JNI(即一般说的
Native 方法)引用的对象


  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值