JVM学习笔记

JVM机制
JVM包含 类加载子系统,垃圾回收系统GC ,内存三部分。

=================================
运行数据区(内存)
运行数据区分为5个组件:方法区,堆区域,堆栈区,PC寄存器,本地方法堆栈。
方法区:类级别的数据存储在这里 。方法区里存的都是类型信息,也就是类的信息,而类的信息 又包括以下内容:

   类的全限定名(类的全路径名) 
   类的直接超类的全限定名(如果这个类是Object,则它没有超类) 
   这个类是类型(类)还是接口 
   类的访问修饰符,如publicabstract、final等 
   所有的直接接口全限定名的有序列表(假如它实现了多个接口) 
   常量池 
   字段、方法信息、类变量信息(静态变量)   
   装载该类的装载器的引用(classLoader)、
   类型引用(class)

堆区域: 所有对象及其对应的实例变量和数组将存储在这里(涉及到后续的GC)
JVM中只有一个方法区,一个堆区域,是共享资源。方法区是线程安全的,堆区域是线程非安全的。堆栈区 对于每个线程都将新创建一个栈,对于每个方法的调用,将在堆栈存储器中产生一个条目,称为堆栈帧。所有局部变量将在堆栈内存中创建。
类的对象放在heap(堆)中,所有的类对象都是通过new方法创建,创建后,在stack(栈)会创建类对象的引用(内存地址)。一种常规用途的内存池(也在RAM(随机存取存储器 )区域),其中保存了Java对象。和栈不同:“内存堆”或“堆”最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,
也不必知道存储的数据要在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。要求创建一个对象时,只需用new命令编辑相应的代码即可。执行这些代码时,会在堆里自动进行数据的保存。
当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间。
Java栈:Java栈的区域很小,只有1M,特点是存取速度很快,所以在stack中存放的都是快速执行的任务,基本数据类型的数据,和对象的引用(reference)。驻留于常规RAM(随机访问存储器)区域。但可通过它的“栈指针”获取处理的直接支持。栈指针若向下移,会创建新的内存;若向上移,则会释放那些内存。这是一种特别快、特别有效的数据保存方式,仅次于寄存器。创建程序时,Java编译器必须准确地知道堆栈内保存的所有数据的“长度”以及“存在时间”。这是由于它必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活性,所以尽管有些Java数据要保存在栈里——特别是对象句柄,但Java对象并不放到其中。
JVM只会直接对JavaStack(Java栈)执行两种操作:①以帧为单位的压栈或出栈;②通过-Xss来设置, 若不够会抛出StackOverflowError异常。
1.每个线程包含一个栈区,栈中只保存基本数据类型的数据和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本数据类型的变量区、执行环境上下文、操作指令区(存放操作指令)。
栈是存放线程调用方法时存储局部变量表,操作,方法出口等与方法执行相关的信息,Java栈所占内存的大小由Xss来调节,方法调用层次太多会撑爆这个区域。
程序计数器(ProgramCounter)寄存器 :PC寄存器( PC register ):每个线程启动的时候,都会创建一个PC(Program Counter,程序计数器)寄存器。PC寄存器里保存有当前正在执行的JVM指令的地址。
每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。保存下一条将要执行的指令地址的寄存器是 :PC寄存器。PC寄存器的内容总是指向下一条将被执行指令的地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。

=================================
类加载器子系统 Java类的加载,链接,初始化。在java类加载时,而非编译时。

加载 是按规定好的文件路径顺序加载jar包,加载类
链接 对前面一步加载生成的字节码文件是否正确
初始化 静态变量赋予原始值,并且执行静态代码块

Java的类加载器有哪些?
类加载机制并非只使用单个的类加载器。每个Java程序至少拥有三个类加载器:引导类加载器,扩展类加载器,系统类加载器(应用类加载器)。
每个类加载器都加载哪些类?
引导类加载器负责加载系统类(通常从JAR文件rt.jar中进行加载)。它是虚拟机整体中的一部分,而且通常用C语言类实现的。引导类加载器没有对应的ClassLoader对象,例如,该方法 String.class.getClassLoader()将返回去null。
扩展类加载器用于从jre/lib/ext目录加载“标准的扩展”。可以将JAR文件放入该目录,这样即使没有任何类路径,扩展类加载器也可以找到其中的各个类。
系统类加载器用于加载应用类。它在由CLASSPATH环境变量或者-classpath命令行选项设置的类路径中的目录里候着是JAR/ZIP文件中查找这些类。
这些类加载器之间的父子关系怎样?
类加载器有一种父/子关系。除了引导类加载器外,每个类加载器都有一个父类加载器。根据规定,类加载器会为它的父类加载器提供一个机会,以便加载任何给定的类,并且只有在其父类加载器加载失败的时候,它才会加载给定类。
例如,当要求系统类加载器加载一个系统类(比如,java.util.ArrayList)时,它首先要求扩展类加载器进行加载,该扩展类加载器则首先要求引导类加载器进行加载。引导类加载器查找并加载rt.jar中的这个类,而无须其他类加载器组做更多的搜素。
什么是双亲委派模型?
双亲委派模型(Parents Delegation Model)的要求是除了顶层启动类加载器外,其余的类加载器都有自己的父类加载器。
为什么Java的类加载器要使用双亲委派模型?
有了双亲委派模型,黑客自定义的java.lang.String类永远都不会被加载进内存。因为首先是最顶端的类加载器加载系统的java.lang.String类,最终自定义的类加载器无法加载java.lang.String类。
如何自定义自己的类加载器?
我们可以编写自己的用于特殊目的的类加载器,这使得我们可以在虚拟机传递字节码之前执行定制的检查。例如,我们可以编写一个类加载器,它可以拒绝加载没有标记为“paid for”的类。
如果我们要编写自己的类加载器,只需要继承ClassLoader类,然后覆盖如下方法 findClass(String className)
自己的类加载器和Java自带的类加载器关系如何处理?

附加追问问题:
1、什么是类加载?什么时候进行类加载?
2、什么是类初始化?什么时候进行类初始化?
3、什么时候会为变量分配内存?
4、什么时候会为变量赋默认初值?什么时候会为变量赋程序设定的初值?
5、类加载器是什么?
6、如何编写一个自定义的类加载器?

=================================
GC的连环炮
什么时候一个对象会被GC?为什么要在这种时候对象才会被GC?
java堆内存中存放着对象实例,垃圾收集器GC在对堆进行回收前,首先要先判断这些实例是否还活着,可以用引用计数算法和可达分析法来判断
1.引用计数算法
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。目前主流的java虚拟机都摒弃掉了这种算法,最主要的原因是它很难解决对象之间相互循环引用的问题。尽管该算法执行效率很高。
2.可达性分析算法
这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。
GC的策略都有哪些分类?
分代收集器 :JVM在进行GC时,内存中存在新生代 Young Generation,老年代Old Generation,永久代 PermGen
新生代包括三个区Eden, From(surviver1) ,To(surviver2)
一个对象首先在Eden中生成,然后传入From,然后To, GC在在新生代中非常频繁。
老年代 一般存放几次GC仍然存活的对象,还有比较大的对象,生命周期比较长的对象。
对象生命周期类比人类的年龄,新创建的对象放入新生代的Eden,老的放入老年代 Old Generation
永久代: 永久代存放类的定义,类的字节码
这些策略分别都有什么优劣势?都不适用于什么场景?

=================================

堆,栈,方法区的画图?
(特别留意:栈内存储内容以及栈帧)
https://blog.csdn.net/qian520ao/article/details/78952895

=================================

jvm调优:gc如何查询CPU使用率?
https://www.cnblogs.com/xiexy/p/8298415.html

类加载时期的链接的过程?
栈的底层实现?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值