微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JVM理解



jvm 核心机制

一、 类加载器

作用 加载 class file 文件

类是模板抽象的 而对象是实际存在的

在这里插入图片描述

  1. 虚拟机自带的加载器

  2. 启动类加载器 根加载器

  3. 扩展类加载器

  4. 应用程序加载器

  5. 双亲委派机制

在这里插入图片描述

机制是 jvm会去一层一层找 如果上层有同样的方法 则会用上层的

应用程序加载器 app —>扩展加载器 exc—>boot加载器 (根加载器)

如果扩展加载器和根加载器都没有的情况下 才回去用到我们的应用加载器所实现的

  1. 类加载器收到类加载请求
  2. 将这个请求委托给父类加载去完成 一直向上委托 直到启动类加载器
  3. 启动类类加载器会检查是否能加载此类 如果可以就加载 执行结束 如果不行就抛出异常就向子类传递加载 直到能加载即可

二 沙箱安全机制

字节码校验器 确保java编写过程规范性 这样可以使java程序内存保护 核心类就不会经过字节码校验

类装载器(class loader):其中类装载器在三个方面对沙箱起作用

  • 它防止恶意代码干涉善意的代码
  • 它守护了被信任的类边界库
  • 它将代码归入保护域 确定了代码可以进行那些操作

类装载器采用的就是双亲委派机制

  1. 最内层的jvm自带类加载器开始加载 外层同名类就得不到加载器的加载
  2. 由于严格通过包来区分访问域 外层恶意的类通过内置代码也无法获取权限访问到内层类 破坏代码就自然无法生效了
    • 存取控制器 (access controller): 存取控制器可以控制核心api对操作系统的存取权限而这个控制的设定 可以由用户来指定
    • 安全管理器(security package) :最核心api和操作系统的主要接口 实现权限控制 比存取控制器优先级别更高
    • 安全软件包(security package)java.security下的类和扩展包下的类 允许用户为自己的应用增加新的安全特性 包括
      • 安全提供者
      • 消息摘要
      • 数字签名 keytools
      • 加密
      • 鉴别

三 native 方法

1 native 介绍

public class Thread {
    public static void main(String[] args) {


    }

    /**
     * native 凡是加了native关键字的 说明java范围作用达不到了 会去调用c语言的库
     * 会进入到本地方法栈 native method stack
     * 调用本地方法接口 jnI
     * JNI的作用就是扩展 java使用 融合不同的编程语言提供java使用
     * java诞生时  c c++ 横行 想要立足必须要有调用c c++的程序
     * 它在内存中专门开辟一块标记的区域 native method stack 登记native方法 而并不能执行
     * 在最终加载本地方法库中的方法 通过JNI
     * 
     * java程序驱动打印机 管理系统常见 roboot 企业很不常见
     * 现在可以利用 通信实现  socket webservice http
     */
   
    private native void start0();
}

2 pc寄存器

1 线程私有 就是一个指针 执向方法区的方法字节码 然后每次加1 是非常小的内存单元

3 方法

method area

方法区是被线程共享 所有字段字节码 以及一些特殊方法 如构造函数,接口代码也在此定义 简单说 所有定义的方法信息都保存在该区域 此区域属于共享区间

静态常量 变量 类信息(构造方法 接口定义),运行时常量池存在方法区中 但是 实例变量存在堆内存中 和方法区无关static final class 常量池

jvm运行流程图

在这里插入图片描述

jvm有几种

hotspot 这个是我们常用的jdk自带

BEA jrockit

IBM j9vm

Heap 一个jvm只有一个堆 堆内存的大小是可以调节的

类加载器读取了类文件后 堆里有什么?

方法 常量 变量 以及引用的实例对象

在这里插入图片描述

GC垃圾回收主要存在 新生区和养老区 新生区垃圾回收(轻GC)养老区垃圾回收(重GC)

假设内存满了 就会报OOM错误 因为最后养老区也满了

JDK 8 以后 永久存储区改名为(元空间)

在这里插入图片描述

真理 经过研究 99%的对象都是临时的

永久区

这个区域内存常驻 用来存放jdk的class对象 和 interface元数据 存放java运行环境 这个区域不存在垃圾 vm关闭释放内存

  • jdk 1.6之前: 永久代 常量池是在方法
  • jdk 1.7 :永久代 永久代 在慢慢退化 去永久化 常量池在堆里
  • jdk 1.8之后 :无永久代 常量池在元空间里

在这里插入图片描述

可以手动对堆内存调优 -xms1024m -xms1024m -XX:+PrintGCDetail 这是将堆内存 最大和初始调为1024

(元空间 逻辑上存在 物理上其实是不存在的 “非堆”)

OOM报错 通常都是内存问题

  1. 调大内存
  2. 分析逻辑上内存的问题
package java.com;

import java.util.Random;

/**
 * @author hp
 制造死循环 出现oom
 */
public class demo1 {
    public static void main(String[] args) {
        String str="aasdsada";
        while (true){
            str+=str+ new Random().nextInt(1111111111)+new Random().nextInt(1111111);
        }
    }


}
   /**
         * 堆内存调优
         * -xms1024m -xms1024m XX:+PrintGCDetail
         * 改大堆内存
         */
        public static void main(String[] args) {
            long max = Runtime.getRuntime().maxMemory(); //最大内存
            long total = Runtime.getRuntime().totalMemory();//初始化内存大小

            System.out.println("max"+max+"字节\t"+(max/(double)1024/1024)+"mb");
            System.out.println("total"+total+"字节\t"+(total/(double)1024/1024)+"mb");
        }

一个项目中 突然出现了oom怎么解决

  • 能够看到是第几行代码出错(内存快照分析工具)mat jprofiler

  • debug 一行行分析很慢

    mat jprofiler作用

  • 分析内存文件 快速定位内存泄漏

  • 获得堆中的数据

  • 获取大的对象 。。。

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid18720.hprof ...
Heap dump file created [7855930 bytes in 0.014 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.Demo03.<init>(Demo03.java:9)
	at com.Demo03.main(Demo03.java:15)
    //jvm似乎能捕获 堆溢出的错误
public class Demo03 {
    /**
    xms 设置初始化内存大小  认1/64
    xmx 设置最大分配内存 1/4
    -xx:+printGCDetails 打印gc
     * -xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError 
     */
    byte[] array=new byte[1*1024*1024]; //1m
    public static void main(String[] args) {
        ArrayList<Demo03> list=new ArrayList<>();
        int count=0;
        try {
            while (true){
                list.add(new Demo03()); //这个工具主要看线程 能定位到准确问题地方
                count=count+1;
            }
        }catch (Exception e){
            e.printstacktrace();
        }


    }

GC

GC主要作用于堆里

JVM在进行GC时,并不是对这三个区域统一回收。大部分时候回收都是新时代

  • 新生区
  • 幸存区(from to) 动态的会交替进行
  • 老年区

GC两种类 轻 GC( 普通GC) 重GC(全局GC)

GC题目:

  • jvm的内存模型和分区 详细每个区放什么?
  • 堆里面分区有哪些 eden from to 老年区 说说他们的特点
  • 特点:eden 特点就是创建对象都会在这里创建 from to动态替换 老年区存放在from to活下来的对象 】
  • GC的算法有哪些? 标记清除法 标记压缩,复制算法,引用计数法 怎么用的
  • 轻GC 重GC分别在什么时候发生

1.引用计数法

在这里插入图片描述

因为每个对象都要给一个计数器 所以非常耗费资源

2.复制算法

在这里插入图片描述

动态展示

在这里插入图片描述

其实就是把第一次存活的复制到 to 然后在把第一次from的存活的也复制到to 然后它自己为空 就变成了TO

  • 好处:没有内存碎片 统一存放
  • 坏处:浪费了内存空间 有一半空间永远为空 假设100%存活 极端

复制算法最佳使用 存活率较低的地方 新生区就是最佳使用场景

3.标记清除(压

在这里插入图片描述

(压缩)算法

  • 好处 :不需要额外的空间
  • 坏处 :两次扫描严重浪费时间 会产生垃圾碎片

压缩

在这里插入图片描述

标记清理几次轻GC 在进行压缩 减少碎片

总结

内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)

内存整齐度:复制算法=标记压缩算法>标记清除算法

内存利用率:标记压缩算法=标记清除算法>复制算法

难道没有最优算法嘛?

答案:没有 只有最合适的算法----》GC:分代收集算法

年前代

  • 存活率低
  • 复制算法

老年代

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐