JAVA:【基础四】JVM

  1. 谈一下对jvm的理解

    1. jvm是存在于操作系统上(Linux,Windows,Mac)的
    2. java程序是跑在jvm上的
    3. jvm是用c语言实现的
    4. 安装JRE即包含安装了jvm环境,如果只是跑程序不需要安装jdk
    5. jvm一共有三种:
      1. sun公司的Hotspot,可通过java -version查看当前jvm版本
      2. IBM的J9VM JIT编译器
      3. BEA的 JRockit
  2. jvm的体系结构

    1. JAVA:【基础四】JVM_第1张图片 JVM模型
    2. class loader:类加载器
    3. 根据《Java 虚拟机规范》中的说法,Java 虚拟机的内存结构可以分为【公有】和【私有】两部分。
      1. 私有指的是每个线程的私有数据,包括:PC寄存器、Java 虚拟机栈、本地方法栈

      2. 公有指的是所有线程都共享的部分,指的是 Java 堆、方法区、常量池

  3. Class Loader类加载器【重要!】

    1. 类加载器工作流程JAVA:【基础四】JVM_第2张图片

    2. 类加载器作用
      1. 加载编译后的class文件
      2. 加载后生成【可实例化对象实例的class模版类对象】
        1. // carClass即为类模版对象
          Class carClass = Car.class;
          Car car = carClass.newInstance();
      3. 根据类模板对象【实例化对象】(new  对象)
      4. class模版类对象 与 普通类对象区别:
        1. 一个class文件对应一个class模板类对象,即不管Car.class执行多少个carClass,这些carClass都是同一个class模板对象
    3. java类加载器的类型
      1. Bootstrap Loader:启动类加载器,也叫根加载器,其可加载到的类对应jre环境中rt目录下的jar包
      2. ExtClassLoader:扩展类加载器,其可加载到的类对应jre环境中EXC目录下的jar包
      3. AppClassLoader:应用程序加载器,即开发人员自定义的类,这些类会生成对应的应用程序加载类,比如Student加载类
    4. 类加载器的加载机制
      1. 双亲委派机制:
        1. jvm接收到加载class文件的请求
        2. 先使用【启动类加载器】加载该class文件,如果需要加载的类的全包名在rt下存在,则使用启动类加载器加载rt下的类
        3. 再使用【扩展类加载器加载】
        4. 最后【使用应用程序加载器】
        5. 比如:新建一个 java.lang.String类,但是该类与【启动类加载器】中的String类重包且重名,则此时使用String类时,就会使用rt下的String类
      2. 沙箱安全机制
        1. 目的:防止恶意代码被执行
  4. native关键字
    1. 凡是带了native关键字的方法,说明这java的作用范围达不到了,会去调用底层C语言的库;
    2. 凡是带了native关键字的,会进入native本地方法栈,然后调用本地方法接口【JNI-Java native interface】
    3. JNI作用:扩展Java的使用,融合不同的编程语言为Java所用,比如C、C++
  5. 程序结束器【线程独有】
    1. 每个线程都有一个程序计数器,作用是记住当前线程执行的位置。
  6. 方法区【全局共享】
    1. 方法区可以看成是一个接口,对于方法区的实现,不同虚拟机中策略也不同。以我们常用的HotSpot虚拟机为例,其设计团队使用永久带来实现方法区,并把GC的分代收集扩展至永久带
    2. 方法区中保存:
      1. JAVA:【基础四】JVM_第3张图片 JDK1.6
      2. JAVA:【基础四】JVM_第4张图片 JDK1.7
      3. JAVA:【基础四】JVM_第5张图片 JDK1.8
  7. 栈【线程独有】

    1. 栈:首先是一种数据结构。
      1. 栈、多线程、方法的关系
        1. 可以将栈看成一个桶,固放入到栈中的东西总是【先入后出】
        2. 一个线程对应一个独立的栈内存,栈中包含多个方法【即栈帧】,当前方法执行结束时,当前栈帧就会被弹出栈内存,从而继续进行下一个栈帧的运行。

          JAVA:【基础四】JVM_第6张图片

        3. 如果在main方法中存在多线程,那么内存模型如下。这样就保证了各个线程之间互不影响JAVA:【基础四】JVM_第7张图片
    2. 为什么main方法先执行,但总是最后结束?
      1. 先将main方法放到栈中
      2. 如果在main方法中调用A方法,于是将A方法也放入栈中,压在main方法上
      3. 如果在A方法中也调用B方法,同理将B方法也放入栈中,压在A方法上
      4. 当B方法执行完成后,将B方法弹出栈
      5. 接着继续执行A方法,当A方法执行结束时,将A方法弹出栈
      6. 接着继续执行main方法,当main方法执行结束时,将main方法也弹出栈,至此,main方法执行结束
    3. 栈的生命周期和线程同步,线程结束,占内存也被释放了。固栈中不存在垃圾回收问题
    4. 栈里面存储哪些东西
      1. 属于八大基本类型的局部变量的值(String、类等属于引用类型,固栈中不存放String)【存在于栈帧中】
      2. 属于引用类型的局部变量的引用(该引用指向的对象分配在了堆中)【存在于栈帧中】
      3. 实例的方法【栈帧本身】
    5. 如果栈中线程的深度 > 栈允许的总深度:StackOverFlowError【属于错误,错误会使程序停掉】
  8. 堆(Heap)

    1. 堆:先进先出,FIFO~>first into first out
    2. 一个jvm只有一个堆
    3. 堆内存大小是可以调节的
    4. 类加载器加载了class文件后,会向堆中存放哪些东西呢
      1. 几乎所有的对象实例对象数组都在堆中分配
      2. 属于八大基本类型的成员变量,其引用和值均存在堆中的类对象里面(String、类等属于引用类型,固栈中不存放String)
      3. 属于引用类型的成员变量,其引用和对象 均存在堆中的类对象里面
      4. 综合23来说,不管成员变量是基本类型还是引用类型,其引用、值或者是对象均存在与堆中
      5. jdk1.7以后,还保存了字符串常量池静态变量
      6. 垃圾回收主要就是作用于这里的
  9. 堆中备份为三个区域
    1. JAVA:【基础四】JVM_第8张图片
    2. 堆中垃圾回收机制:Minor GC和Major GC区别
      1. Minor GC:简单理解就是发生在年轻代的GC。三步(复制--清空--互换)
      2. Major GC又称为Full GC。当年老代空间不够用的时候,虚拟机会使用“标记—清除”或者“标记—整理”算法清理出连续的内存空间,分配对象使用。
    3. 新生代【Young】
      1. 新生区占对空间的1/3,包含:伊甸园区【Eden Space】、Survivor From区、Survivor To区,其比例为8:1:1
      2. 伊甸园区:Java大部分新创建的对象都会被分配在伊甸园区,如果对象太大则会直接分配到老年区,当伊甸园区的内存不够时,会触发Minor GC复制算法的GC回收对象
      3. 新生区的处理机制:
        1. 第一次Yong GC(Minor GC)后,Eden区还存活的对象复制到Surviver区的“To”区,“From”区还存活的对象也复制到“To”区,
        2. 再清空Eden区和From区,这样就等于“From”区完全是空的了,而“To”区也不会有内存碎片产生,
        3. 等到第二次Yong GC时,“From”区和“To”区角色互换,很好的解决了内存碎片的问题。
        4. 对象在Survivor区中每“熬过”一次GC,年龄就会+1。待到年龄到达一定岁数(默认是15岁),虚拟机就会将对象移动到年老代
    4. 老年代【Old】
      1. 主要存放应用程序中生命周期长的内存对象
      2. 老年代的对象比较稳定,所以MajorGC不会频繁执行
      3. MajorGC采用标记清除算法:首先扫描一次所有老年代,标记出存活的对象,然后回收没有标记的对象。MajorGC的耗时比较长,因为要扫描再回收。MajorGC 会产生内存碎片,为了减少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。当老年代也满了装不下的时候,就会抛出OOM (Out of Memory)异常
    5. 永久区【Perm,JDK1.7以前】
      1. 内存的永久保存区域,主要存放Class 和Meta (元数据)的信息
      2. GC不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的Class 的增多而胀满,最终抛出OOM异常。
    6. 元空间【jdk1.8及以后】
      1. 在jdk1.8以后,jvm使用元空间替代了永久区,固1.8的jvm模型如下:JAVA:【基础四】JVM_第9张图片
      2. 区别:元空间的内存使用的本地的物理内存,不再使用jvm的堆内存
      3. 元空间保存:类信息、运行时常量池

你可能感兴趣的:(JAVA,java,jvm内存模型,java,堆,栈模型)