标签:Java 标记 算法 理解 GC 内存 JVM 深入 加载
JVM
-
JVM的位置
-
JVM的体系结构
-
类加载器
- 作用:加载Class文件
加载步骤:- 类加载器收到请求
- 将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器
- 启动加载器检查是否能够加载当前这个类,能加载就结束,使用当前加载器,否则,抛出异常,通知子加载器进行加载
- 重复步骤3
- 作用:加载Class文件
-
- 虚拟机自带的加载器
- 启动类(根)加载器
- 扩展类加载器
- 应用程序加载器
Java无法调用线程相关东西,用native方法调用c++ - 百度:双亲委派机制
- 定义:当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。
- 作用:
-
- 防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
-
- 保证核心.class不能被篡改。通过委托方式,不会去篡改核心.clas,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。
- 保证核心.class不能被篡改。通过委托方式,不会去篡改核心.clas,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。
-
沙箱安全机制
-
Java1.1增加,给定权限后能够使用
-
字节码校验器:确保Java类文件尊循Java语言规范。这样可以帮助Java程序实现内存保护。但并不是所有的类文件都会经过字节码校验, 比如核心类
-
类装载器:在3个方面对Java沙箱起作用
-
- 防止恶意代码去干涉善意代码 //双亲委派机制
-
- 守护了被信任的类库边界
-
- 将代码归入保护域,确定了代码可以进行哪些操作
虚拟机为不同的加载器载入的类提供了不同的命名空间,命名空间由一系列唯一的名称组成,每一个被装载的类将有一个名字,这个命名空间是由Java虚拟机为每一个类装载器维护的,他们之间甚至不可见。
-
存储器控制器:存取控制器可以控制核心API对操作系统的存取权限,而这个控制的策略的设定可以由用户指定
-
安全管理器:是核心API和操作系统之间的主要接口。实现权限控制。比存取控制器优先级高。
-
安全软件包:java.security下的类和扩展包下的类,允许用户为自己增加新的安全特征,包括:
- 安全提供者
- 消息摘要
- 数字签名 keytools
- 加密
- 鉴别
-
-
native关键字
- 凡带了native关键字的方法,说明Java的作用范围达不到了,回去掉用底层C语言的库!
- 会进入本地方法栈
- 调用本地方法接口 JNI
- JNI作用:扩展Java的使用,融合不同的汇编语言为Java所用!
- Java诞生的时候,C、C++横行,想要立足,必须要有调用C、C++程序
- 它在内存区域中专门开辟了一块标记区域:Native Method Stack,登记native方法
- 最终执行的时候,加载本地方法库中的方法通过JNI
- Java程序驱动打印机,管理系统,掌握即可,在企业应用中较为少见
- 调用其他接口:Socket,WebService~…http~
-
PC寄存器
- 每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来指向一条指令的地址,也即将要执行的指令码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略
-
方法区
被所有线程共享
静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但实例变量存在堆内存中,和方法区无关
static final Class 常量池
-
栈
- 数据结构
- 程序=数据结构+算法:持续学习~
- 程序=框架+业务逻辑:吃饭~
- 栈:先进后出,后进先出:桶
- 队列:先进先出(FIFO:first input ,first output)
- 为什么main()先执行,最后结束
- 栈:栈内存,主管程序的运行,生命周期和线程同步;
- 线程结束,栈内存也就是释放,对于栈来说,不存在垃圾回收问题,一旦结束,栈就over!
- 栈:8大基本类型+对象引用+实例方法
- 栈运行原理:栈帧
- 程序正在执行的方法,一定在栈的顶部
- 栈+堆+方法区:交互关系
三种JVM
- Sun公司 HotSpot
- BEA公司 JRockit
- j9vm
我们学习的都是HotSpot
堆
-
Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的
-
类加载器读取了类文件后,一般会把什么东西放在堆中?
- 类,方法,常量,变量,保存我们所有引用类型的真实对象;
-
堆内存还要细分三个区域:
- 新生区(伊甸园区)满了触发重GC Full GC:
- 类:诞生和成长的地方,甚至死亡
- 伊甸园Eden Space:所有的对象都是在这 new出来的 满了触发轻GC,幸存留在幸存区
- 幸存区0区、幸存1区。
- 99%对象都是临时对象!!!
- 养老区:
- 永久区:这个区域常驻内存的,用来存放JDK自身携带的Class对象。Interface元数据,存储的是Java运行时的一些环境或信息,这个区域不存在垃圾回收!关闭vm虚拟机就会释放这个区域内存
一个启动类,加载了大量的第三方Jar包,Tomcat部署了太多的应用,大量动态生成的反射类。不断被加载。直到内存满,就会出现OOM;- jdk1.6之前:永久代,常量池是在方法区
- jdk1.7:永久代,但是慢慢的退化了,
去永久代
,常量池在堆中 - Jdk1.8之后:无永久代,常量池在元空间
GC垃圾回收,主要是在伊甸园区和养老区
假设内存满了,OOM,堆内存不够
JDK8以后,永久存储区改名为元空间
默认情况,分配的总内存是电脑的1/4,而初始化的内存:1/64
OOM解决:
-
扩大堆内存,看结果
-Xms 设置初始化内存分配大小 1/64
-Xmx 设置最大分配内存, 默认1/4
-XX:+PrintGCDetails 打印GC垃圾回收信息
-XX:+HeapDumpOnOutOfMemoryError
-
分析内存,看一下哪里有问题
- 能够看到第几行代码出错:内存快照分析工具,MAT,Jprofiler
- Dubug,一行行分析代码
MAT,Jprofilter作用:
- 分析Dump内存文件,快速定位内存泄漏
- 获得堆中的数据
- 获得大的对象
- 新生区(伊甸园区)满了触发重GC Full GC:
GC垃圾回收
G C
JVM在进行GC时,并不是对三个区域统一回收。大部分时候,回收都是新生代
- 新生代
- 幸存区(from,to)
- 老年区
GC两种类:轻GC(普通),重GC(全局)
题目:
- JVM的内存模型和分区,详细到每个区存放什么?
- 堆里面的分区有哪些?Eden,from,to,老年区,说说他们的特点!
- GC的算法有哪些?标记清除法,标记整理法,复制算法,引用计数器,怎么用的?
- 轻GC和重GC分别在什么时候发生?
引用计数法
复制算法
-
幸存区:谁空谁是to,每次GC都会将Eden中活的对象移到幸存区中:一旦Eden区被GC后,就回事空的
-
当一个对象经历了15次GC,都还没有死
-
-XX:MaxTenuringThreshold=9999,通过这个参数可以设定进入老年代的时间
-
好处:没有内存的碎片
-
坏处:浪费了内存空间:多了一半空间永远是空“to”,假设对象100%存活(极端情况)
复制算法使用场景:对象存活度较低;新生区
标记清除算法
- 优点:不需要额外的空间
- 缺点:两次扫描,严重浪费时间,会产生内存碎片
总结
- 内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)
- 内存整齐度:复制算法=标记压缩算法>标记清除算法
- 内存利用率:标记压缩算法=标记清除算法>复制算法
思考:难道没有最优算法?
答案:没有最好的算法,只有最合适的算法---->GC:分代收集算法
年轻代:
- 存活率低
- 复制算法
老年代:
- 区域大:存活率
- 标记清除(内存碎片不是太多)+标记压缩混合
标签:Java,标记,算法,理解,GC,内存,JVM,深入,加载 来源: https://blog.csdn.net/wqgwc/article/details/118764193
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。