jvm体系结构

黄色:所有线程共享、占用空间较大,存在垃圾回收

灰色:各个线程独享数据区域、占用空间较小,不存在垃圾回收

1575783857812

类装载器ClassLoader

是什么

负责加载class文件,class文件在文件开头有特定的文件标示,将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构并且ClassLoader只负责class文件的加载,至于它是否可以运行,则有Execution Engine决定。

1575784373433

类装载器类型

虚拟机自带的加载器

  • 启动类加载器(Bootstrap)C++
  • 扩展类加载器(Extension)Java
  • 应用程序类加载器(AppClassLoader)Java也叫系统类加载器,加载当前应用的classpath的所有类

用户自定义加载器

  • Java.lang.ClassLoader的子类,用户可以定制类的加载方式

1575784997347

演示一

1575790437359

双亲委派

双亲委派模型的式作过程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完全这个加载请求时,子加载器才会尝试自己去加载。

沙箱安全

沙箱机制是由基于双亲委派机制上 采取的一种JVM的自我保护机制,假设你要写一个java.lang.String 的类,由于双亲委派机制的原理,此请求会先交给Bootstrap试图进行加载,但是Bootstrap在加载类时首先通过包和类名查找rt.jar中有没有该类,有则优先加载rt.jar包中的类,因此就保证了java的运行机制不会被破坏

演示二

1575790989071

本地接口

 本地接口的作用是融合不同的编程语言为Java所用,它的初衷是融合C/C++程序,Java诞生的时候是C/C++横行的时候,要想立足,必须有调用C/C++程序,于是就在内存中专门开辟了一块区域处理标记为native的代码,它的具体做法是Native Method Stack中登记native方法,在Execution Engine执行时加载native libraties

  目前该方法使用的越来越少了,除非是与硬件有关的应用,比如通过Java程序驱动打印机或着Java系统管理生产设备,在企业级应用中已经比较少见。应为现在的异构领域间的哦通信很发达,比如可以使用Socket通信,也可以使用Web Service等等,不多做介绍。

本地方法栈

 它的具体做法是Native Method Stack中登记native方法,在Execution Engine执行时加载本地方法库。

演示三

线程的start方法调用了start0方法就是一个本地方法,只有声明没有实现

1575791717214

程序计数器

类似排班值日表

1575791524021

方法区

  • 所有线程共享,存在垃圾回收
  • 存类模板信息(Car Class)
  • 方法区是一种规范
    • Java7是永久代
    • Java8是元空间
  • 实例变量存在堆内存中,和方法区无关

Java栈

栈管运行,堆管存储

队列(FIFO)先进先出

(FILO)先进后出

Java栈保存:8种基本数据类型、对象的引用变量、实例方法

Java中层面main方法是程序的入口,main方法会被保存到Java栈中,Java栈中层面叫做栈帧

演示四

方法递归调用,栈溢出

1575794149620

栈、堆、方法区的交互关系

创建对象的过程Object obj = new Object()obj存储在Java中,实例对象数据存储在中,实例对象数据是由类模板创建出来的,类模板存储在方法区

1575794350515

堆结构

逻辑上分

  • 新生代
    • 伊甸区
    • 幸存0区
    • 幸存1区
  • 老年代
  • 永久代(Java7)、元空间(Java8),方法区是一种规范,永久代或者是元空间是方法区的不同落地实现

对于HotSpot虚拟机,很多开发者习惯将方法区称之为“永久代(Parmanent Gen)” ,但严格本质上说两者不同,或者说使用永久代来实现方法区而已,永久代是方法区(相当于是一个接口interface)的一个实现,jdk1.7的版本中,已经将原本放在永久代的字符串常量池移走。

1576051892566

物理上则排除了永久代或者是元空间

1576051849603

证明堆结构

package com.zbiti.jvm;

public class HeapStructureDemo {
    public static void main(String[] args) {
        //返回 Java 虚拟机试图使用的最大内存量。
        long maxMemory = Runtime.getRuntime().maxMemory();
        //返回 Java 虚拟机中的内存总量。
        long totalMemory = Runtime.getRuntime().totalMemory();
        System.out.println("MAX_MEMORY = " + maxMemory + "(字节)、" + (maxMemory / (double) 1024 / 1024) + "MB");
        System.out.println("TOTAL_MEMORY = " + totalMemory + "(字节)、" + (totalMemory / (double) 1024 / 1024) + "MB");
    }
}

添加VM options :-XX:+PrintGCDetails

1576052345574

控制台输出

可以看到输出了堆结构:新生代PSYoungGen、老年代ParOldGen、元空间Metaspace,那如何知道物理上堆结构只包含新生代和老年代呢

新生代加上老年代的和38400K+87552K=125952K

堆内存的默认初始化大小128974848字节128974848/1024=125952K,因此可知物理上堆结构只包含新生代和老年代

1576053646764

堆内存调优

Java7

1576054181737

Java8

1576054230377

参数 说明
-Xms 设置初始分配大小,默认为物理内存的1/64
-Xmx 最大分配内存,默认为物理内存的1/4
-XX:+PrintGCDetails 输出详细的GC处理日志

修改堆参数,模拟堆溢出

-Xms1024m -Xmx1024m -XX:+PrintGCDetails,设置堆初始值和最大值一样,避免峰值的低、高抖动

package com.zbiti.jvm;

import java.util.Random;

public class HeapSpaceDemo {
    public static void main(String[] args) {
        String str = "com.zbiti.com";
        while(true){
            str+=str+new Random().nextInt(88888888)+new Random().nextInt(999999999);
        }
    }
}

1576200018621

控制台

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

1576199860861

4大垃圾回收算法

1576203461842

JVM在进行GC时,并非每次都对上面三个内存区域一起回收的,大部分时候回收的都是指新生代。因此GC按照回收的区域又分了两种类型,一种是普通GC(minor GC),一种是全局GC(major GC or Full GC)

  • 普通GC(minor GC):只针对新生代区域的GC,指发生在新生代的垃圾收集动作,因为大多数Java对象存活率都不高,所以Minor GC非常频繁,一般回收速度也比较快。
  • 全局GC(major GC or Full GC):指发生在老年代的垃圾收集动作,出现了Major GC,经常会伴随至少一次的Minor GC(但并不是绝对的)。Major GC的速度一般要比Minor GC慢上10倍以上

引用计数法

1576293394802

复制算法(Copying)

使用在新生代

1576293534032

绿色:空闲的堆内存空间(新生代)

红色:可回收的垃圾对象

黄色:对象已经占用的堆内存空间

蓝色:堆内存空间(老年代)

1576293674987

标记清除(Mark-Sweep)

使用在老年代

1576294271165

1576294283136

标记压缩(Mark-Compact)

使用在老年代,比标记清除多一步压缩

1576295775283

本文由博客一文多发平台 OpenWrite 发布!

posted @ 2019-12-15 19:22 libingshen 阅读(145) 评论(0) 推荐(0)
摘要: 生产环境服务器变慢,诊断思路和性能评估 整机:top 代码 top命令查看 CPU:vmstat id:处于空闲的CPU百分比 wa:系统等待IO的CPU时间百分比 st:来自于一个虚拟机偷取的CPU时间百分比 查看额外的CPU信息 所有CPU核信息 每个进程使用CPU的用量分解信息 内存:free 阅读全文
posted @ 2019-11-06 20:52 libingshen 阅读(712) 评论(1) 推荐(1)
摘要: NodeJS入门 NodeJS模块 http模块 server.js server2.js js const http=require('http'); const fs=require('fs'); let server=http.createServer((req, res)= { fs.rea 阅读全文
posted @ 2019-11-06 20:44 libingshen 阅读(305) 评论(0) 推荐(0)
摘要: 1、查询用户拥有的权限 子查询和连接查询2种,比较推荐连接查询,子查询比较影响性能,子查询看起来比较容易理解,而连接查询需要比较熟悉各个表之间的关系 sql SELECT DISTINCT p. FROM t_permission p LEFT JOIN t_role_permission trp 阅读全文
posted @ 2019-11-06 20:35 libingshen 阅读(180) 评论(0) 推荐(0)
摘要: 数据表结构设计 唯一索引unique,保证数据唯一性 sql CREATE TABLE ( int(11) NOT NULL AUTO_INCREMENT COMMENT '用户表id', varchar(50) NOT NULL COMMENT '用户名', varchar(50) NOT NUL 阅读全文
posted @ 2019-11-04 20:21 libingshen 阅读(2354) 评论(0) 推荐(2)
摘要: ThreadLocal中保存的数据只能被当前线程私有,不被其它线程可见 证明 声明一个全局的变量 ,初始值为 ,通过 个线程对其进行访问修改设置,理论上 的最终值应该是 ,然而我们的输出结果是 ,说明了 中存放的数据是各自线程私有的 编写过滤器 类,通过在 方法中对 进行存数据 编写 类,在业务中可 阅读全文
posted @ 2019-11-02 14:23 libingshen 阅读(285) 评论(0) 推荐(0)
摘要: Windows系统安装svn 1、svn下载 https://sourceforge.net/projects/win32svn/ 2、验证是否安装成功 3、创建版本库 4、启动svn服务 5、验证svn服务是否启动 svn服务监听3690端口 6、svn注册为Windows服务 tip:等号左边没 阅读全文
posted @ 2019-11-02 14:20 libingshen 阅读(1202) 评论(0) 推荐(0)
摘要: 策略模式和工厂模式的搭配使用可以很好地消除代码 的多层嵌套 需求 针对店下商铺,有这样一个需求,对用户客户分为了普通客户、 客户、超级 用户、专属 用户 个等级,每当用户购买商品时,针对不同的用户等级和消费金额采取不同的打折优惠策略。在平常的开发当中,必然会出现多层的 嵌套判断,先判断用户的等级再判 阅读全文
posted @ 2019-11-02 14:18 libingshen 阅读(13882) 评论(2) 推荐(1)
摘要: 简介 是什么 参考教程:http://mp.baomidou.com/guide/ "MyBatis Plus" (简称 MP)是一个 "MyBatis" 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 特性 无侵入 :只做增强不做改变,引入它不会对现有工程产生 阅读全文
posted @ 2019-11-02 14:10 libingshen 阅读(747) 评论(0) 推荐(1)
摘要: 限制搜索 in 关键词限制搜索范围 | 命令 | 说明 | | | | | xxx in:name | 项目名包含xxx的 | | xxx in:description | 项目描述包含xxx的 | | xxx in:readme | 项目的readme文件中包含xxx的 | | xxx in:na 阅读全文
posted @ 2019-09-30 09:54 libingshen 阅读(290) 评论(0) 推荐(0)
点击右上角即可分享
微信分享提示