JVM自学部分总结

JVM:
1.JVM内区域存划分-6大区域
线程私有内存:程序计数器,java虚拟机栈,本地方法栈
线程私有指的是:这三块区域生命周期与线程的生命周期相同,随着线程的创建而创建,随着线程的销毁而回收,
不同线程之间这三块内存彼此隔离
1).程序计数器
当前线程正在执行的字节码行号指示器,唯一一块不会产生OOM(OutOfMemoryError)异常的区域,若执行的是Native方法,计数器值为0;
2).虚拟机栈-java方法的内存模型
每个方法从调用到执行完的过程,就对应一个栈帧在JVM中入栈与出栈过程
一共产生两种异常StackOverFlowError,OOM(OutOfMemoryError)
3).本地方法栈-native方法的内存模型:
HoSpot:本地方法栈与虚拟机栈合二为一
线程共享内存:
线程共享:所有线程共享此三块内存区域,彼此不隔离

1).java堆(GC堆,垃圾回收的主要负责区域):
存放所有对象实例以及数组空间
-Xmx:设置堆的最大值
-Xms: 设置堆的最小值
2).方法区
存放JVM加载的类信息,常量,静态变量,JDK8之前称之为“永久代”

3).运行时常量池
是方法区的一部分,存放字面量与符号引用
字面量:直接写出来的值
符号引用:(符号引用->找到指定类,在通过引用变量到堆空间)

OOM的产生原因:
内存泄漏:产生的对象永远无法被垃圾回收;

 内存溢出:当前的堆的空间过小,没有足够容纳新的对象的空间,适当的扩大堆的大小基本就可解决问题

2.垃圾回收策略:(回收针对的线程共享内存(堆,方法区))
2.1.那些对象需要回收

判断对象是否存活??
a.引用计数器法(Python C++智能指针)
给每个对象附加一个引用计数器,每当有一个引用指向当前对象,计数器+1;每当有引用不在只想当前该对象,计数器-1;任意时刻,引用计数器的值为0,是的对象就被标记为不再“存活”。
缺点:无法解决循环引用问题

b.可达性分析算法(java,c#,lisp)
通过一系列称为GC Roots对象开始向下搜寻,若到指定对象有路可走(“可达”),认为此对象存活;
若从任意一个GCRoots对象到目标对象均不可达,认为目标对象已经不再存活。

哪些对象可以作为GC Roots:
虚拟机栈与本地方法栈中的临时变量指向的对象
类中静态变量引用的对象
类中常量引用的对象

面试题:JDK1.2以后关于引用的扩充?
强引用:程序中普遍存在的,GC Roots对象指向的引用都属于强引用(只要当前对象被任意一个强引用指向,即便内存不够用也不能回收此对象)

     软引用: 软引用是用来描述一些还有用但是不是必须的对象。对于软引用关联着的对象,在系统将要发生 内存溢出之前,会把这些对象列入回收范围之中进行第二次回收。
                    如果这次回收还是没有足够的内存,才 会抛出内存溢出异常。在JDK1.2之后,提供了SoftReference类来实现软引用

     虚引用: 虚引用也被称为幽灵引用或者幻影引用,它是弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,
                  也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用的 唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
                  在JDK1.2之后,提供了 PhantomReference类来实现虚引用。 

     弱引用:弱引用也是用来描述非必需对象的。但是它的强度要弱于软引用。被弱引用关联的对象只能生存 到下一次垃圾回收发生之前。当垃圾回收器开始进行工作时,
                  无论当前内容是否够用,都会回收掉只被弱引用关联的对象。在JDK1.2之后提供了WeakReference类来实现弱引用。 

2.2.当一个对象到GC Roots不可达,就一定会当场去世?(finalize())
a.若没覆写,此对象直接被回收
b.若对象所在的类覆写了finalize()
I.若finalize()未被JVM调用,会调用finalize(),若对象在此次调用中与GC Roots有路可走,此对象不再被回收
II.若finalize()已被JVM调用,此对象直接被回收
2.3.已经死亡的对象如何进行垃圾回收??
方法区回收:(废弃常量和无用的类)
回收废弃常量和回收Java堆中的对象十分类似。以常量池中字面量(直接量)的回收为例,
假如一个字符串"abc"已经进 入了常量池中,但是当前系统没有任何一个String对象引
用常量池的"abc"常量,也没有在其他地方引用这个字面量, 如果此时发生GC并且有
必要的话,这个"abc"常量会被系统清理出常量池。常量池中的其他类(接口)、方法、
字段的 符号引用也与此类似。

3 堆-垃圾回收算法:
3.1.标记-清除算法:
两个阶段:
标记:将需要回收的对象打上回收标记
清除:一次性回收所有打上标记的对象空间
最大缺点:标记-清除会产生大量的不连续空间碎片,导致GC频繁发生。

堆(所有对象和数组对象)
–新生代:大部分对象在此区域存放,该区域特点“对象朝生夕死”(存活率很低)
–老年代:存活率很高
3.2.复制算法(新生代回收算法)*****************
将新生代内存分为一块较大的Eden和两块较小的Survivor(幸存者)空间,
每次使用Eden和其中一块Survivor(两个 Survivor区域一个称为From区,
另一个称为To区域)。当回收时,将Eden和Survivor中还存活的对象一次性
复制到 另一块Survivor空间上,后清理掉Eden和刚才用过的Survivor空间。
当Survivor空间不够用时,需要依赖其他内存(老年代)进行分配担保

复制算法的核心流程:
step1:对象默认都在Eden区产生,当Eden区空间即将满时,触发第一次MinorGC(新生代GC),
将Eden区所有存活对象复制到From区,然后一次性清理掉Eden区的所有空间
step2:当Eden区再次爆满的时候,触发minor GC ,此时需要将Eden与from区的所有存活对象复制到To区,
然后一次清理掉Eden与From的所有空间,之后的新生代GC,重复阶段2.
备注:默写对象来回在From与To区交换若干次(默认15次)以上,将其置入老年代。。
3.3标记整理算法(老年代的垃圾回收算法)
核心思想相较于标记-清除:整理阶段先让存活对象先向存活对象一端移动,而后清理掉存活对象边界之外的所有空间

4.分代收集策略(javaGC)
将堆空间分为新生代(Xmn)与老年代空间,其中新生代采用复制算法,老年代采用标记整理算法。

JVM内置的监测工具
jps:返回当前操作系统中的所有的JVM进程ID jps -l(输出包名,类名)
jmap:查看当前JVM的内存情况 jmap -heap PID(查看PID的JVM的堆情况)
jstack:查看当前JVM的线程栈情况,常用于解决线程卡死问题;

5.java内存模型
主要是定义JVM如何将变量存储到内存中,又如何从内存中的变量取回等细节
变量(线程共享):类中的实例属性,静态属性以及数组元素。
5.1.所有变量必须存储在主内存中
5.2.每个线程的内存叫做工作内存,工作内存中保存了使用使用到主内存的变量的副本
5.3.线程对于变量的所有操作必须在工作内存中进行,而不能直接操作主内存,不同的线程之间也无法访问彼此的工作内存,变量间的值传递均通过主内存来进行;

内存模型的三大特性:

原子性 : 由Java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store和read。
大致可以认为,基本数据类型的访问读写是具备原子性的。如若需要更大范围的原子性,
需要synchronized关键字约束。(即一个操作或者多个操作 要么全部执行并且执行的过
程不会被任何因素打断,要么就都不执行)
可见性 : 可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。volatile、
synchronized、?nal三个关键字可以实现可见性。
有序性 : 如果在本线程内观察,所有的操作都是有序的;如果在线程中观察另外一个线程,所有的
操作都是无序 的。前半句是指"线程内表现为串行",后半句是指"指令重排序"和"工作内
存与主内存同步延迟"现象。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值