精华内容
下载资源
问答
  • 深入jvm虚拟机

    2018-08-14 14:58:22
    本书讲述了Java虚拟机一运行 所有Java程序的抽象计算机,还讲了几种与虚拟机密切相关的核心Java API。本书通过分析讲解、可运行的示例、参考资料和applet (它作为文中所述概念的交互式例示),提供了Java技术的深人...
  • 深入介绍jvm
  • JVM虚拟机源码(C++)

    2018-07-29 17:40:56
    最新版jdk7的hotspot源码,对于每一个希望深入研究JVM实现和原理的同学,是宝贵的资料
  • JVM虚拟机图片

    2018-01-03 17:16:32
    JVM虚拟机JVM虚拟机JVM虚拟机JVM虚拟机JVM虚拟机JVM虚拟机JVM虚拟机JVM虚拟机JVM虚拟机JVM虚拟机JVM虚拟机JVM虚拟机
  • JVM 虚拟机.md

    2019-09-05 19:17:56
    JVM 学习,包含运行数据区域,GC,JMM 等常见问题
  • JVM虚拟机详解

    千次阅读 多人点赞 2020-04-12 00:02:59
    不了解JVM的Java程序员无异于蒙上双眼在沼泽地奔跑的犀牛,你永远不知道你会在什么时候会掉进坑里,也永远不会明白为什么会掉进坑里。 那么,今天你是蒙着双眼奔跑的么?

    前排提示:文章内容过多,请耐心阅读或根据目录获取所需内容

    前方高能

    由于脑图比较长,可能部分用户无法看清内容,关注公众号:不会修电脑,获取本文所有脑图资源

    1.JVM相关

    1.1.概述

    JVM是Java Virtual Machine的缩写,中文意思是Java虚拟机。能来看这篇文章的人应该大多都玩过Windows或Linux虚拟机,JVM跟他们的功能也类似:提供一个虚拟的计算机环境,来运行一些程序。
    我们都知道,Linux与Windows软件是不通用的,但是如果我们在一台Windows设备上安装了Linux虚拟机,那我们就也可以开心的在Windows上使用Linux软件了,思路延伸一下:所有能够安装JVM的机器都可以运行Java程序。Java语言使用JVM屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。这就是“一次编译,多次运行”。

    1.2.本质

    JVM说到底,其实就是在物理机上运行的程序,同时他依托物理机而拥有了完善的硬件架构和指令系统。

    1.3.扩展

    当下来看,JVM已经有了相当完善的技术体系,如符合开放接口标准的各种API、优化技术等。

    这里是一段防爬虫文本,读者请忽略。
    本文最先由Baldwin_Keepmind发表于CSDN,转载请注明出处。
    作者博客地址:https://blog.csdn.net/shouchenchuan5253
    

    2.JVM运行时数据区

    2.1.虚拟机栈

    虚拟机栈是每个Java方法的内存模型,虚拟机栈中元素叫做“栈帧”,每一个方法被执行的时候都会压入一个栈帧,执行完毕则出栈,这个栈帧里面存放着这个方法的局部变量表(包括参数)、操作栈、动态链接、方法返回地址。

    我们需要知道的是,局部变量表是在编译的时候就确定大小了,我们在调用一个方法时,局部变量表的大小是已知且确定的,在方法执行的时候不会改变局部变量表的大小

    我们常说的Java内存中的栈内存一般就是指的局部变量表部分。如果变量是基本类型,会直接保存在这个区域,如果是引用类型,那会保存对象的引用地址

    2.2.本地方法栈

    Navtive方法是Java通过JNI直接调用本地C/C++库。

    本地方法栈(Native Method Stacks)我们可以理解为本地方法的虚拟机栈。他的功能与虚拟机栈类似,只是本地方法栈是为了本地方法服务而不是Java方法(字节码)。JVM通过C/C++暴露给Java的接口来调用本地方法,当线程调用本地方法时,JVM虚拟机栈不会变,更不会进行压栈操作,JVM只是简单地动态连接并直接调用指定的native方法。

    *本地方法栈是一个后入先出栈(LIFO)
    *本地方法栈是线程的私有栈,随线程启动而生,线程结束而死
    

    2.3.程序计数器

    程序计数器是每个线程所私有的一小块区域,其中记录了当前线程执行到的字节码的行数(当前程序执行的位置),字节码解释器工作时需要根据当前程序执行的位置来判断下一行要执行的程序。
    上面我们说过,JVM中会执行两种方法:java方法和本地方法,在执行不同方法时,程序计数器的表现是不一样的。执行Java方法,计数器工作,其中储存着正在执行的字节码指令的地址;如果当前执行的是本地方法,那程序计数器将会储存空值。这里强调一下:程序计数器区域是虚拟机规范中唯一不存在OutOfMemoryError的内存区域

    作用

    *字节码解释器选择下一条指令:字节码解释器通过程序计数器的值来判定下一条指令的地址,从而来实现代码的流程控制。
    *多线程中的指令位置恢复:线程私有的计数器记录当前线程的位置,在C这个线程重新执行的时候,可以恢复到线程上次停止的地方继续执行。想象一下,如果没有程序计数器,那线程被唤醒的时候该是多么的迷茫与无助。
    

    2.3.Java堆

    Java堆是JVM中占内存最大的一块区域,他在虚拟机启动时创建,是所有线程所共享的一块区域。

    堆的任务就是存放所有的对象实例,几乎所有的对象实例都储存在这里。他可以分为年轻代永生代,同时Java堆也是GC工作的主要区域,有时候我们也叫他GC堆。

    年轻代

    年轻代又分为三部分edenFrom SurvivorFrom Survivor,默认情况下这三部分大小按照8:1:1(比例可配置,将在JVM调优中讲到)分布,整个年轻代又占Java堆的1/3。
    年轻代的三个模块按照8:1:1是有一定道理的,这与等下要讲到垃圾回收有关系。
    大多数对象都在年轻代中创建,而且在年轻代中的对象大多数生命周期很短。
    在新生代中,并不是每次存活的对象都少于10%,有时候若是存活的对象大于10%,就会想老年代进行空间分配担保。

    老年代

    在新生代中经过N(N可配置,默认15)次垃圾回收仍然存活的对象就会被放进老年代,老年代中的对象存活率都比较高。

    2.4.元数据区(永久代)

    它用于存储虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,是各个线程共享的内存区域。

    在JDK8之前的HotSpot JVM,存放这些”永久的”的区域叫做“永久代(permanent generation)”。永久代是一片连续的堆空间,在JVM启动之前通过在命令行设置参数-XX:MaxPermSize来设定永久代最大可分配的内存空间,默认大小是64M(64位JVM默认是85M)。

    这里是一段防爬虫文本,读者请忽略。
    本文最先由Baldwin_Keepmind发表于CSDN,转载请注明出处。
    作者博客地址:https://blog.csdn.net/shouchenchuan5253
    

    3.JVM垃圾回收算法(GC)

    3.1.标记-清除算法

    标记-清除算法是最基本的回收算法,该算法分两个步骤:标记、清除。 首先将那些不可到达的对象进行标记,然后将有标记的对象进行清除,复制-清除算法不是一个比较好的算法,他有两个比较严重的问题
    *标记清除算法过后的内存空间有很多碎片,如果下次有一个较大的对象需要实例化时,虽然新生代中的内存足够储存它,但因为没有足够的连续空间,JVM会再次调用GC。
    *标记和清除的过程效率都比较低,
    

    3.2.复制算法

    模型

    复制算法将内存空间分为两个区,所有的对象实例都储存在其中一个区(活动区间),而另一个区叫做(空闲区间)。

    过程

    当活动区间的内存空间不足时,JVM将会暂停程序的运行,开启复制算法的GC线程。GC线程将活动区间内所有存活的实例复制到空闲区间(依次排列),完成复制后活动区间的指针指向原空闲区间,空间区间的指针指向原活动区间,此时完成了两个区间的对换,同时一次性清除原活动区间中的对象,待下次GC开启时重复上面的操作。

    使用场景

    复制算法优化了标记-清除算法中的两个问题,特别适合那些对象存活率很低的内存空间,比如新生代,新生代中绝大多数对象的都是朝生夕死的。

    上文我们说过,新生代的三个空间不是平均分配的,原因就在这里,对象都在Eden中创建,Eden内存空间不足时就开始使用一个S区来进行复制算法GC(新生代的GC又叫做Minor GC),GC结束后Eden区间就被清空了,大部分对象都无法到达S区,所以S区相对于Eden区就不需要那么大的空间。

    当GC过程中使用的那个S区满了之后,这个区里面还不能晋升的对象就会复制到另一个S区中。

    3.3. 标记-整理算法

    标记-整理算法也分两步:标记、整理

    所谓标记,就是标记不可达对象。整理指的是,将存活的对象往一端移动,然后清理掉存货对象边界以外的对象,从而达到GC的目的。 其实移动的效率也不高,但是如果需要移动的对象比较少,那标记-整理算法也是个好办法。

    使用场景

    老年代中的对象大多数都是存活率比较高的对象,如果老年代使用复制算法,那每次GC都将需要在复制的过程中耗费大量时间,老年代用的就是标记-整理算法。

    3.4. GC算法总结

    标记的存活对象将会被整理,按照内存地址依次排列,而未被标记的内存会被清理掉。如此一来,当我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可,这比维护一个空闲列表显然少了许多开销。

    不难看出,标记/整理算法不仅可以弥补标记/清除算法当中,内存区域分散的缺点,也消除了复制算法当中,内存减半的高额代价。

    不过任何算法都会有其缺点,标记/整理算法唯一的缺点就是效率也不高,不仅要标记所有存活对象,还要整理所有存活对象的引用地址。从效率上来说,标记/整理算法要低于复制算法。

    3.5. GC新生代晋升老年代的情形(内存分配)

    3.5.1.新生代满

    我们知道新生代在进行GC时,会向两个S区转移对象,但是当两个S区都已经没有空间,那就无法将新生代的对象再转移到S区,这时候就会分配担保机制将新生代中的对象直接晋升到老年代。

    3.5.2. 对象过大

    新生代产生了一个对象,这个对象大小大于规定的最大对象大小(在Serial及ParNew中可通过-XX:PretenureSizeThreshold配置),新生代在就不会保存这个对象,而是绕过新生代,直接在老年代为该对象分配空间。

    3.5.3. 满足晋升条件

    虚拟机中的每一个对象都有对象年龄(Age)计数器,当对象的年龄达到晋升条件(年龄到达-XX:MaxTenuringThreshold配置值)时,就会在GC时晋升代老年代。

    3.5.4. 动态对象年龄判断

    当在S区中处于某一个年龄的对象占用了很大内存空间(大于S区大小的1/2)时,大于或等于该年龄的对象将直接进入老年代,而不是等年龄到达晋升年龄才进入老年代

    这里是一段防爬虫文本,读者请忽略。
    本文最先由Baldwin_Keepmind发表于CSDN,转载请注明出处。
    作者博客地址:https://blog.csdn.net/shouchenchuan5253
    

    4. JVM异常

    JVM异常主要是StackOverFlowError和OutofMemoryError(OOM)。

    4.1. StackOverFlowError(栈溢出)

    StackOverFlowError的出现表明:程序因为某些原因已经把JVM分配给线程的栈耗尽

    4.1.1. 原因

    最常见的导致栈溢出的原因是程序里的递归,递归执行的过程中会反复的调用自己,在制定跳出递归条件时一定要慎重,避免出现死递归在虚拟机栈中给递归方法分配的栈帧深度是有限的,递归方法会不断的在这个栈帧的局部变量表中写入数据,最终到达栈低,然后抛出栈溢出Error.

    4.1.2. 死递归示例

    代码

    public class StackOverTest {
        static long l = 0L;
    
        public static void printT(){
            System.out.println(l);
            l++;
            //死递归
            printT();
        }
    
        public static void main(String[] args) {
            printT();
        }
    }
    

    结果

    .......
    8847
    8848
    8849
    *** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
    Exception in thread "main" java.lang.StackOverflowError
        at java.io.PrintStream.write(PrintStream.java:480)
        at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
        at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
        at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
        at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
        at java.io.PrintStream.write(PrintStream.java:527)
        at java.io.PrintStream.print(PrintStream.java:611)
        at java.io.PrintStream.println(PrintStream.java:750)
        at Prototype.StackOverTest.printT(StackOverTest.java:7)
        at Prototype.StackOverTest.printT(StackOverTest.java:10)
        at Prototype.StackOverTest.printT(StackOverTest.java:10)
        ......
    

    4.1.3. 解决办法

    *合理设置跳出递归的条件,避免死递归
    *如果你确定你递归的条件没有问题,可能只是你的程序需要递归的次数比较多,默认的线程栈大小可能是 512KB 或者 1MB。那么你可以使用 -Xss 标识来增加线程栈的大小,参数的格式:-Xss<size>[g|G|m|M|k|K]
    

    4.1.4.关于死循环导致的栈溢出

    网上资料有很多观点是死循环也会引起栈溢出,这种说法是不准确的,正确的说法是,死循环中不断向内存中放置新对象的情形才会导致栈溢出

    本质上来说,所有的操作系统都是一个死循环,那么我们的程序中出现死循环时,我们就要谨慎考虑死循环中的资源的申请与释放,避免因死循环而导致的栈溢出。

    4.2. OutOfMemoryError(OOM)

    OOM直白点的意思就是内存用完了

    4.2.1 原因

    当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error。发生OOM的原因根本在于两点

    *JVM内存分配少:JVM内存达不到我们程序所需要的内存,那程序在运行的时候就会OOM
    *程序内存得不到释放:应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。
    

    内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用。

    内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。

    得益于Java的GC机制,我么不用手动其释放资源,理论上是不会发生内存泄露的。但是有些程序逻辑上有漏洞,GC机制无法清理某些对象,当这些存活的对象大小超过JVM的内存时,就会会出现内存溢出。

    最近工作中恰巧出现了内存溢出的情景,在这里跟大家分享一下,因为有保密协议,所以这里不再贴源码,只是描述一下

    在我的代码中,我引入了一个缓存机制,把所有的用户类实例都放到这个系统缓存区,便于下一次用户进来的时候直接访问,设计程序时没有考虑太多,所以没有设置缓存失效时间,程序刚上线的时候设置缓存区的效果很好,减少了用户访问登录的时间,但是最近我们的用户量激增,每次项目启动一周后都会邮件警示,我们修改代码重新上传后系统又能保持一段时间,但一周左右又开始警示,于是我专门抽出来一天加班来检查错误,最终是检查到了BUG,就是由于这个系统缓存区存放了太多的User对象,昨天已经将更新过的代码上传,现在看是否还会发生同样的问题。
    

    4.2.2. 常见OOM及解决办法

    Java堆内存溢出

    这个算是比较常见的OOM了,在Java一般是由于堆内存分配不足引起的。可以通过虚拟机参数-Xms,-Xmx等修改对内存大小来避免这个问题。

    永久代(元数据)溢出

    一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区,同时常量过多也会引起永久代溢出。与堆内存类似,我们也可以通过参数来修改永久代的内存大小,比如-XX:PermSize=64m -XX:MaxPermSize=256m。

    4.3. JVM异常总结

    “知己知彼,百战不殆”我们了解了JVM异常发生的原因,那么解决他也不是那么困难了。

    这里是一段防爬虫文本,读者请忽略。
    本文最先由Baldwin_Keepmind发表于CSDN,转载请注明出处。
    作者博客地址:https://blog.csdn.net/shouchenchuan5253
    

    5.Java类文件结构

    首先希望你把类与对象的关系搞清楚,类文件是一组以8位字节为基础单位的二进制流,他是由.Java文件编译而来的,而对象是根据类来创建的,你可以把类理解为对象的模板。

    5.1.Class平台无关性

    Class文件运行于JVM上,只要平台安装有JVM虚拟机即可,与平台的类型无关。

    5.2. Class类结构

    整个Class文件本质上就是一张表,它由如下所示的数据项构成。

    Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件中,中间没有添加任何分隔符,这使得整个Class文件中存储的内容几乎全部都是程序运行的必要数据。根据Java虚拟机规范的规定,Class文件格式采用一种类似于C语言结构体的伪结构来存储,这种伪结构中只有两种数据类型:无符号数和表。无符号数属于基本数据类型,以u1、u2、u4、u8来分别代表1、2、4、8个字节的无符号数。表是由多个无符号数或其他表作为数据项构成的符合数据类型,所有的表都习惯性地以“_info”结尾。

    从表中可以看出,无论是无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器加若干个连续的该数据项的形式,称这一系列连续的某一个类型的数据为某一类型的集合,比如,fields_count个field_info表数据构成了字段表集合。这里需要说明的是:Class文件中的数据项,都是严格按照上表中的顺序和数量被严格限定的,每个字节代表的含义,长度,先后顺序等都不允许改变

    由于篇幅有限,本章有许多内容只做大致介绍,本章参考内容:https://blog.csdn.net/ns_code/article/details/17675609

    5.2.1. magic

    每个Class文件的头四位数据被称为魔数,他的唯一作用是判断这个文件是不是能够被JVM运行的.class文件,.class文件的头四位应该被固定为0xCAFEBABE,就是大佬口中说的咖啡宝贝。我们打开一个.class文件来验证一下

    5.2.2. minor_version

    这2个字节存储的是Class文件的次版本号
    在上面那张图中我们可以看着,这2个字节的值是:00 00,这个次版本号目前还没有明确的含义,可能是设计者留用的。

    5.2.3. major_version

    这两个字节储存着class文件的主版本号,我们可以看出,我们这个class的主版本号是:00 34,他作为16进制数对应着十进制的52,这是对应着JDK8.详情可以去了解一下JDK版本对照表,以下是我一些对应信息

    5.2.4.constant_pool_count

    这是下面常量池的计数器,占用一个字节,代表常量池容量计数值,这个容量计数值是从1开始而不是从0开始的

    5.2.5 constant_pool

    常量池中主要存放两大类常量:字面量和符号引用,常量池可以理解为Class文件之中的资源仓库,它是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一,同时还是在Class文件中第一个出现的表类型数据项目。

    字面量

    字面量比较接近于Java层面的常量概念,如文本字符串、被声明为final的常量值等。

    符号引用

    而符号引用总结起来则包括了下面三类常量

        类和接口的全限定名(即带有包名的Class名,如:cn.yzstu.testClass)
        字段的名称和描述符(private、static等描述符)
        方法的名称和描述符(private、static等描述符)
    

    常量池的内容也比较多,大多数时候我们或许没有必要这么深入,在此也不再详细描述。

    5.2.6. access_flag

    用来标记类或接口的访问信息。

    主要信息:这个Class是类还是接口,是否定义为public类型,abstract类型,如果是类的话,是否声明为final,等等。每种访问信息都由一个十六进制的标志值表示,如果同时具有多种访问信息,则得到的标志值为这几种访问信息的标志值的逻辑或。

    5.2.7. this_class

    类索引,用于确定这个类的全限定名。

    5.2.8. super_class

    父类索引,用于确定这个类的父类的全限定名。

    Java规定,不允许多重继承,所以父类索引只有一个,除了java.lang.Object之外,所有的Java类都有父类,因此除了java.lang.Object外,所有Java类的父类索引都不为0。

    5.2.9 interfaces_count

    类的接口计数器

    5.2.10. interfaces

    接口索引集合,里面描述了当前类实现了哪些接口,这些被实现的接口将按implements语句(如果这个类本身是一个接口,则应当是extends语句)后的接口顺序从左到右排列在接口的索引集合中。

    5.2.11. fields_count

    字段计数器

    5.2.12. fields

    字段表(field_info)用于描述接口或类中声明的变量。字段包括了类级变量或实例级变量,但不包括在方法内声明的变量。字段的名字、数据类型、修饰符等都是无法固定的,只能引用常量池中的常量来描述。

    5.2.13. methods_count

    方法表的计数器

    5.2.14. methods

    方法表(method_info)的结构与属性表的结构相同。

    5.2.15 attributes_count

    属性表的计数器

    5.2.16 attributes

    属性表(attribute_info)在前面已经出现过多系,在Class文件、字段表、方法表中都可以携带自己的属性表集合,以用于描述某些场景专有的信息。

    6. JVM调优

    有句话叫做“绝大部分项目用不到JVM调优”,我是很赞同这句话的。在实际参与项目的过程时,我很少用到JVM调优,但是耐不住每次面试必问,所以还是深入了解了下JVM调优。

    这里是一段防爬虫文本,读者请忽略。
    本文最先由Baldwin_Keepmind发表于CSDN,转载请注明出处。
    作者博客地址:https://blog.csdn.net/shouchenchuan5253
    

    6.1. 调优简介

    6.1.1. 何时需要调优

        *程序运行时堆内存常常被占满
        *频繁的进行Full GC(一天内GC超过一次)
        *GC时间过长(超过1S)
        *系统引入的本地缓存过大
        *程序运行时出现OOM/StackOverFlowError
        *系统吞吐量不高
    

    6.1.2. 调优时的注意事项

        *建议少的或不使用JVM调优(不正确的调优参数往往导致系统性能下降)
        *调优之前应先检查是否是自己的代码逻辑出错,减少使用调优
        *优先考虑减少全局变量和大对象,其次考虑调优
        *调优时应先在本地多次试验,选取最合适的调优参数,再将调优参数应用在生产环境
    

    总的来说,能不用就不用

    6.1.3.JVM调优目标示例

        *堆内存占用少于70%
        *老年代内存占用少于50%
        *GC占时小于1S
        *不进行Full GC或一天Full GC少于1次
    

    6.2. 调优参数简介

    本章参考文章:https://www.cnblogs.com/qlqwjy/p/8037797.html

    JVM不稳定参数

    在JVM中 -XX 被称为不稳定参数,参数的值会明显的改变JVM性能,当然性能的改变是两方面的,如果你找到了一系列合适的参数,那么很可能JVM性能会大范围的提高,但是如果参数不合适,那么也会降低JVM性能。不稳定参数主要分三种:

    布尔类型参数

    -XX:+ < option>  '+'表示启用该选项
    
    -XX:-< option> '-'表示关闭该选项
    

    数字类型参数值:

       -XX:<option>=<number> 给选项设置一个数字类型值,可跟随单位,例如:'m'或'M'表示兆字节;'k'或'K'千字节;'g'或'G'千兆字节。
    

    字符串类型参数值:

        -XX:<option>=<string> 给选项设置一个字符串类型值,通常用于指定一个文件、路径或一系列命令列表。
    

    6.3. 常见调优思想

    将对象留在新生代

    新生代GC是Minor GC,Minor GC相比于Full GC来说成本比较低,所以在JVM中可以合理设置一个新生代空间,减少Full GC。

    大对象在老年代申请空间

    新生代需要频繁的进行GC,目前我们已知的是复制算法,如果新生代存在大对象,那GC的代价将是十分巨大的。

    -XX:PretenureSizeThreshold 设置大对象直接进入老年代的阀值,当对象超过这个阀值时,将直接在老年代中分配。只对串行收集器和新生代并行收集器有效,并行回收收集器不识别这个参数。
    

    合适的晋升年龄

    根据自己的系统设置合适的晋升年龄,保证年轻代和老年代中占用的大小比较合适

    -XX:MaxTenuringThreshold:默认值是15,这个参数是指定进入老年代的最大年龄值,对象实际进入老年代的年龄是 JVM 在运行时根据内存使用情况动态计算的,动态计算规则上文已介绍。
    

    堆内存大小

    在实际情况中,对中存放的数据是不断变化的,JVM会根据堆的大小来动态扩展或压缩堆空间。

    -XX:MinHeapFreeRatio:设置堆空间最小空闲比例,默认是 40 ,当堆空间的空闲比例小于这个值时,JVM 便会扩展堆空间
    
    -XX:MaxHeapFreeRatio:设置堆空间的最大空闲比例,默认是 70,当堆空间的空闲比例大于这个值时,JVM 便会压缩堆空间,得到一个较小的堆
    

    当-Xmx 和 -Xms 的值相等时,我们可以获取一个稳定的堆空间,稳定的堆空间对于GC来说是非常有利的。但这不代表震荡的堆空间就不好,动态的控制堆大小,扩展堆空间以减少OOM,压缩堆空间以增加GC速度。

    需要注意的是,当 -Xms 和 -Xmx 相等时,-XX:MinHeapFreeRatio 和 -XX:MaxHeapFreeRatio 这两个参数无效

    回收器选择

    JVM中给出了三种回收器:串行收集器、并行收集器(吞吐量优先)、并发收集器(响应时间优先)。串行选择器只适用于小数据量的情况,这里就不再深入描述。

    -XX:+UseSerialGC:设置串行收集器
    -XX:+UseParallelGC:选择并行收集器(**仅对年轻代有效**)。
    -XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集(**JDK6以上有效**)。
    -XX:+UseParNewGC:选择并发收集器(**仅对年轻代有效,可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值**)。
    -XX:+UseConcMarkSweepGC:设置年老代为并发收集(**-XX:NewRatio=4的配置失效了,此时年轻代大小最好用-Xmn设置**)。
    

    跟踪类或对象

    JVM 提供了一组参数,用于获取系统运行时加载、卸载类的信息,参数设置如下:

    -XX:TraceClassLoading:跟踪类加载情况
    -XX:TraceClassUnloading:跟踪类的卸载情况
    -verbose:class:相当于同时设置  -XX:TraceClassLoading 和 -XX:TraceClassUnloading 两个参数
    -XX:+PrintClassHistogram:打印运行时实例的信息,当设置此参数后,使用 Ctrl +    Break 会输出系统内类的统计信息,从左到右依次显示了序号、实例数量、总大小和类名等信息
    

    控制GC

    -XX:DisableExplicitGC:禁止 GC 操作,即禁止在程序中使用 System.gc() 触发 Full GC
    -Xnoclassgc:禁止类的回收
    -Xingc:增量式的 GC ,增量式的 GC 使用特定的算法让 GC 线程和应用程序线程交叉执行,从而减少应用程序因 GC 产生的停顿时间
    -Xverify:none:关闭类校验器
    -XX:+UseLargePages:启用大页,使用大页后,内存分页的表项就会减少,从而提升CPU从虚拟内存地址映射到物理内存地址的能力
    -XX:LargePageSizeInBytes:指定大页的大小
    

    打印GC信息

    获取GC信息能够帮助我们获取GC执行的情况,从而来针对问题进行调优

    -XX:+PrintGC(-verbose:gc):输出打印简要的 GC 信息,包括GC前的堆栈情况和 GC 后的堆栈大小和堆栈的总大小
    -XX:+PrintGCDetails:输出打印详细的 GC 信息,不仅包括基本信息,还给出了新生代、老年代和永久区各自的 GC 信息
    -XX:+PrintGCTimeStamps:额外输出 GC 发生的时间,可以推断出 GC 的频率和间隔
    -XX:+PrintTenuringDistribution  -XX:MaxTenuringThreshold=18:查看新生代晋升老年代的实际阀值(-XX:+PrintTenuringDistribution),设置的最大年龄为18( -XX:MaxTenuringThreshold=18)
    -XX:+PrintHeapAtGC:每次 GC 时都会打印堆的详细使用情况,输出量很巨大。它分为两个部分:GC 前的堆信息和 GC 后的堆信息,这里包含了新生代、老年代和永久区的使用大小和使用率,还包括了新生代中 eden 区和 survivor 区的使用情况
    -XX:+PrintGCApplicationStoppedTime:应用程序在 GC 发生时的停顿时间
    -XX:+PrintGCApplicationConcurrentTime:应用程序在 GC 停顿期间的执行时间
    -Xloggc:/home/data/jvmgc.log:将 GC 日志信息输出到具体位置的文件中,便于日后日志分析
    

    错误处理

    有时候我们并不知道我们在运行的时候会发生某些错误,保险一点不如加入对OOM错误的处理程序,比如发生OOM是直接重启系统

    -XX:OnOutOfMemoryError=/opt/test/restart.sh
    

    其他

    -XX:+ScavengeBeforeFullGC:新生代GC优先于FullGC执行。
    -XX:-DisableExplicitGC:禁止调用System.gc(),但JVM的gc仍然有效。
    -XX:+MaxFDLimit:最大化文件描述符的数量限制。
    -XX:+UseThreadPriorities:启用本地线程优先级API,即使java.lang.Thread.setPriority()生效,反之无效。
    -XX:SoftRefLRUPolicyMSPerMB=0:“软引用”的对象在最后一次被访问后能存活0毫秒(默认为1秒)。
    -XX:TargetSurvivorRatio=90:允许90%的Survivor空间被占用(默认为50%)。提高对于Survivor的使用率——超过就会尝试垃圾回收。
    

    6.4. JVM调优案例

    常规案例

    我个人针对公司系统提出的优化案例,很可惜没有用上

    -Xms4g:初始堆大小
    -Xmx4g:最大堆大小
    -Xmn2g :年轻代大小 
    -Xss1024K:线程栈大小
    -XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
    -XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
    -XX:MaxPermSize=n:设置持久代大小
    -XX:+UseSerialGC:设置串行收集器
    -XX:+UseParallelGC:设置并行收集器
    -XX:+UseParalledlOldGC:设置并行年老代收集器
    -XX:+UseConcMarkSweepGC:设置并发收集器
    -XX:+PrintGC:打印GC信息
    -XX:+PrintGCDetails:输出打印详细的 GC 信息,不仅包括基本信息,还给出了新生代、老年代和永久区各自的 GC 信息
    -XX:+PrintGCTimeStamps:额外输出 GC 发生的时间,可以推断出 GC 的频率和间隔
    -Xloggc:/home/data/jvmgc.log:将 GC 日志信息输出到具体位置的文件中,便于日后日志分析
    -XX:OnOutOfMemoryError=/opt/test/restart.sh
    

    吞吐量优先案例

    机器配置是 4G 内存 和 32 核 CPU,配置参数如下:

    -Xms3800m  -Xmx3800m(堆的初始值和最大值一样) 
    -Xmn2g(新生代大小)
    -Xss128k(线程栈大小,减少它使剩余的系统内存支持更多的线程) 
    -XX:+UseParallelGC(新生代使用并行回收收集器)
    -XX:ParallelGCThreads=20(垃圾回收的线程数)
    -XX:+UseParallelOldGC (老年代使用并行回收收集器)
    

    降低停顿案例

    为了降低应用软件在垃圾回收时的停顿,首先考虑的使用关注系统停顿的 CMS 回收器,为了减少 Full GC 的次数,应尽可能将对象预留在新生代,新生代 Minor GC 的成本远远小于老年代的 Full GC

    -Xms3800m  -Xmx3800m(堆的初始值和最大值一样) 
    -Xmn2g(新生代大小)
    -Xss128k(线程栈大小,减少它使剩余的系统内存支持更多的线程)
    -XX:ParallelGCThreads=20(垃圾回收的线程数)
    -XX:+UseConcMarkSweepGC(老年代使用 CMS 收集器)
    -XX:+UseParNewGC(新生代使用并行收集器)
    -XX:SurvivorRatio=8(设置 eden : survivor = 8 : 1)
    -XX:TargetSurvivorRatio(设置 survivor 的使用率为 90%,默认是50%,提高了survivor 区的使用率,当存放的对象超过这个数值,则对象会向老年代压缩)
    -XX:MaxTenuringThreshold=31(设置年轻对象晋升到老年代的最大年龄是31,默认是15,设为31是尽可能地将对象留在新生代)
    
    这里是一段防爬虫文本,读者请忽略。
    本文最先由Baldwin_Keepmind发表于CSDN,转载请注明出处。
    作者博客地址:https://blog.csdn.net/shouchenchuan5253
    

    7.常用工具及参数

    7.1. jps(Java Virtual Machine Process Status Tool)

    (画外音:jps是作者接触Java使用的第一个jdk工具,听到这个时我一直以为是“GPS”)

    输出当前运行的所有JVM进程信息(进程ID,进程启动的路径等等),经常使用的参数有4个:

    -m 列出当前虚拟机进程以及传给虚拟机启动主进程main方法的参数
    -l 输出主类的名称
    -v 输出虚拟机启动参数
    -q 只输出虚拟机进程号
    

    jps工具通常配合其他工具一起使用

    7.2. jinfo(Java Configuration Info)

    jinfo命令可以查看和调整某JDK进程的参数,这个命令在进行JVM调优的过程中很重要。

    jinfo [option选项] [PID JVM进程]
    jinfo -flag [JVM参数名称] [PID]
    jinfo -flag +[JVM参数名称] [PID] 使该项参数生效
    jinfo -flag -[JVM参数名称] [PID] 禁用该项参数
    jinfo -flag [JVM参数名称]=[参数的值] 
    

    7.3. jstat(Java Virtual Machine statistics monitoring tool)

    监视JVM运行状态,比如类装载、GC等数据。jstat工具特别强大,有众多的可选项,详细查看堆内各个部分的使用量,以及加载类的数量。使用时,需加上查看进程的进程id,和所选参数。这里仅做简单示例,具体内容请自行查询。

    获取某进程状态使用实例

    当然实际情况中,命令参数不同,指标远不止这些,下面给出jstat指标详情
    S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
    S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
    S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
    S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
    EC:年轻代中Eden(伊甸园)的容量 (字节)
    EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
    OC:Old代的容量 (字节)
    OU:Old代目前已使用空间 (字节)
    PC:Perm(持久代)的容量 (字节)
    PU:Perm(持久代)目前已使用空间 (字节)
    YGC:从应用程序启动到采样时年轻代中gc次数
    YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
    FGC:从应用程序启动到采样时old代(全gc)gc次数
    FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
    GCT:从应用程序启动到采样时gc用的总时间(s)
    NGCMN:年轻代(young)中初始化(最小)的大小 (字节)
    NGCMX:年轻代(young)的最大容量 (字节)
    NGC:年轻代(young)中当前的容量 (字节)
    OGCMN:old代中初始化(最小)的大小 (字节)
    OGCMX:old代的最大容量 (字节)
    OGC:old代当前新生成的容量 (字节)
    PGCMN:perm代中初始化(最小)的大小 (字节)
    PGCMX:perm代的最大容量 (字节)
    PGC:perm代当前新生成的容量 (字节)
    S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
    S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
    E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
    O:old代已使用的占当前容量百分比
    P:perm代已使用的占当前容量百分比
    S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节)
    S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节)
    ECMX:年轻代中Eden(伊甸园)的最大容量 (字节)
    DSS:当前需要survivor(幸存区)的容量 (字节)(Eden区已满)
    TT: 持有次数限制
    MTT : 最大持有次数限制 
    

    7.4. jstack(Java Stack Trace)

    这个工具用来监视JVM线程堆栈的使用情况,在排查问题的过程中很有用。

    命令规范:jstack [ option] PID

    可选操作

    jstack PID 打印出整个JVM堆栈 
    jstack -l PID 除了堆栈,显示关于锁的附加信息
    jstack -m PID 开启mixd mode 即混合模式,还会打印C/C++堆栈
    jstack -F PID 如果jstack正常请求没有响应,强制输出线程堆栈 
    

    7.5. jmap(Java Memory Map)

    监视进程运行中的jvm物理内存的占用情况,该进程内存内,所有对象的情况,例如产生了哪些对象,对象数量。
    jmap命令用于生成heap dump文件,如果不使用这个命令,还可以使用-XX:+HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM的时候自动生成dump文件。 jmap不仅能生成dump文件,还可以查询finalize执行队列、Java堆和永久代的详细信息,如当前使用率、当前使用的是哪种收集器等。jmap参数较多,这里也再详解。

    这里是一段防爬虫文本,读者请忽略。
    本文最先由Baldwin_Keepmind发表于CSDN,转载请注明出处。
    作者博客地址:https://blog.csdn.net/shouchenchuan5253
    

    8.总结

    作者==萌新,如果有错误,欢迎大佬指出。

    看完这篇文章,基本上可以应付大部分工作和面试中的问题了。

    到这里基本上我想要在这篇文章中写的东西已经写完了,还有一些在文章中没有说清楚的内容,后期也会慢慢完善。
    JVM栈工作原理

    我是Baldwin,一个25岁的程序员,致力于让学习变得更有趣,如果你也真正喜爱编程,真诚的希望与你交个朋友,一起在编程的海洋里徜徉!

    往期精选文章

    造轮子的艺术

    源码阅读技巧

    Java注解详解

    教你自建SpringBoot服务器

    更多文章

    未经作者允许,严禁转载本文

    展开全文
  • JVM虚拟机深度讲解

    2018-10-18 14:21:53
    该书对JVM虚拟机深度讲解、详细至极、看了后对JVM的认知度会大幅提升、打通任督二脉
  • JVM虚拟机面试

    2018-07-05 20:35:58
    此资源为jvm的详细介绍,是软件开发人员必须掌握的技术
  • 深入理解jvm虚拟机.txt

    2019-10-16 09:08:18
    深入理解jvm虚拟机
  • jvm虚拟机总结

    2021-01-20 03:21:55
    其中导致这个特性最主要的原因就是java中的jvm虚拟机(引出jvm虚拟机教育他!) JVM是内存中的虚拟机,可以理解为,JVM的存储就是内存,我们所有写的常量,变量,方法都在内存中。 Jvm主要是由类加载器(ClassLoader...
  • 从底层详细讲解了jvm虚拟机的工作机制,包括内存控制、class文件标准、class文件加载,以及运行时数据的处理
  • JVM虚拟机了解

    2017-11-07 16:49:21
    Java基础知识汇总之集合框架List、Map、Set接口及其子类综合对比
  • JVM虚拟机种类

    千次阅读 2019-05-06 16:25:13
    1.Sun Classic VM 2.Exact VM 3.HotSpot VM 4.KVM(Kilobyte) 5.JRockit 6.J9 7.Azul VM 8.Liquid VM 9.Dalvik VM 10.Microsoft JVM

    1.Sun Classic VM

    1.现在此款虚拟机已经淘汰了,是第一款商用的虚拟机。
    2.只能使用纯解释器的方式来执行Java代码。
    

    2.Exact VM

    1.Exact Memory Management准确式内存管理
    2.编译器和解释器混合工作以及两级即时编译器
    3.只在Solaris平台发布
    4.英雄气短,就是存活时间短,被HotSpot取代
    

    3.HotSpot VM

    HotSpot VM的热点代码探测能力可以通过执行计数器找出最具有编译价值的代
    码,然后通知JIT编译器以方法为单位进行编译。 如果一个方法被频繁调用,或方法中有效
    循环次数很多,将会分别触发标准编译和OSR(栈上替换)编译动作。 通过编译器与解释器
    恰当地协同工作,可以在最优化的程序响应时间与最佳执行性能中取得平衡,而且无须等待
    本地代码输出才能执行程序,即时编译的时间压力也相对减小,这样有助于引入更多的代码
    优化技术,输出质量更高的本地代码
    
    

    4.KVM(Kilobyte)

    KVM中的K是“Kilobyte”的意思,它强调简单、 轻量、 高度可移植,但是运行速度比较
    慢。 在Android、 iOS等智能手机操作系统出现前曾经在手机平台上得到非常广泛的应用。
    

    5.JRockit

    1.JRockit VM曾经号称“世界上速度最快的Java虚拟机”
    2.由于专注于服务器端应用,它可以不太关注程序启动速度,因此JRockit内部不包含解析器实现,全部代码都靠即时
    编译器编译后执行。 除此之外,JRockit的垃圾收集器和MissionControl服务套件等部分的实
    现,在众多Java虚拟机中也一直处于领先水平
    

    6.J9

    1.IBM J9 VM并不是IBM公司唯一的Java虚拟机,不过是目前其主力发展的Java虚拟机,IBM J9 VM原本是内部开发代号,
    正式名称是“IBM Technology for Java Virtual Machine”,简称IT4J,只是这个名字太拗口了一点,普及程度不如J9.
    
    2.与BEA JRockit专注于服务器端应用不同,IBM J9的市场定位与Sun HotSpot比较接近,它是一款设计上***从服务器端
    到桌面应用再到嵌入式都全面考虑的多用途虚拟机***,J9的开发目的是作为IBM公司各种Java产品的执行平台,它的主
    要市场是和IBM产品(如IBM WebSphere等)搭配以及在IBM AIX和z/OS这些平台上部署Java
    应用。
    

    7.Azul VM

    Azul VM是Azul Systems公司在HotSpot基础上进行大量改进,运行于Azul Systems公司的
    专有硬件Vega系统上的Java虚拟机,每个Azul VM实例都可以管理至少数十个CPU和数百GB
    内存的硬件资源,并提供在巨大内存范围内实现可控的GC时间的垃圾收集器、 为专有硬件
    优化的线程调度等优秀特性。 在2010年,Azul Systems公司开始从硬件转向软件,发布了自
    己的Zing JVM,可以在通用x86平台上提供接近于Vega系统的特性。
    

    8.Liquid VM

    Liquid VM即是现在的JRockit VE(Virtual Edition),它是BEA公司开发的,可以直接运
    行在自家Hypervisor系统上的JRockit VM的虚拟化版本,Liquid VM不需要操作系统的支持,
    或者说它自己本身实现了一个专用操作系统的必要功能,如文件系统、 网络支持等。 由虚拟
    机越过通用操作系统直接控制硬件可以获得很多好处,如在线程调度时,不需要再进行内核
    态/用户态的切换等,这样可以最大限度地发挥硬件的能力,提升Java程序的执行性能。
    
    

    9.Dalvik VM

    1.Dalvik VM只能称做“虚拟机”,而不能称做“Java虚拟机”,它没有遵循Java虚拟机规范,不能直接执行Java
    的Class文件,使用的是寄存器架构而不是JVM中常见的栈架构。
    2.但是它与Java又有着千丝万缕的联系,它执行的dex(Dalvik Executable)文件可以通过Class文件转化而来,使用Java语
    法编写应用程序,可以直接使用大部分的Java API等。
    
    

    10.Microsoft JVM

    1.微软公司为了在IE3中支持Java Applets应用而开发了自己的Java虚拟机,虽然这款虚拟机只有Windows平台的版本,却
    是当时Windows下性能最好的Java虚拟机。
    
    展开全文
  • JVM虚拟机面试题汇总

    2015-09-25 10:41:58
    经历过很多面试和笔试,看过很多别人的面经,总结了JVM虚拟机的面试题,希望能给面试的童鞋一些帮助。不过,我这里就不想浪费笔墨描述问题的原理了,每个问题都附有答案,如果答案看不懂地方,可以自行百度或者看...
  • JVM虚拟机底层实现原理

    千次阅读 2020-04-09 10:37:13
    JVM虚拟机底层实现 .java文件—>通过javac指令进行编译—>.class文件—>放到jvm上运行。

    JVM虚拟机底层实现

    .java文件—>通过javac指令进行编译—>.class文件—>放到jvm上运行。
    在这里插入图片描述
    根据实例代码分析jvm各个部件的功能:

     public class Math {
    
        public static final int initData = 666;
        public static final User user = new User();
    
        public int compute(){
            int a = 1;
            int b = 2;
            int c = (a+b) * 10;
            return c;
        }
    
        public static void main(String [] args){
            Math math = new Math();
            math.compute();  //将这个位置给jvm
            System.out.println("hello word");
        }
    }
    

    如下图:整个JVM的每个部件的结构和彼此之间的关系。为了便于理解,图像上写了相关注释。
    在这里插入图片描述
    STW(把所有用户线程停掉):jvm触发gc,它会停止用户线程,让gc去收集垃圾。对用户体验感不是太好,对于web网站来说,可能某个用户点击某个按钮,然后停止了用户线程,会出现卡顿的现象。为什么还用它嘞?假设主线程在运行着,当老年代或者年轻代已经放满了,开启gc, 如果不STW,那么gc回收垃圾,主线程继续运行,可能会出现如下情况:主线程中的gc roots引用的对象还存在,它的引用链在主线程没有结束之前,都是有效的对象,同时gc也在运行,当主线程结束之后,gc roots的引用链断开,后续的引用链的对象无效,又变为垃圾对象,那么gc所做的工作效率低下,这会极大影响系统性能,所以在做垃圾回收时,关闭用户线程,让gc安心做垃圾回收。

    为什么要使用程序计数器
    在操作系统中,当开启多线程的时候,假如当前执行的线程cpu被抢占,即线程被挂起,cpu转去执行其它线程的程序,当程序执行结束之后,程序又该往哪里去执行?处理方式是:处理完后返回原来的线程程序继续执行。这就是中断的处理及执行过程,在其他线程抢占cpu之后,将pc(程序计数器)的值压栈或者保存到内存(自动保存,硬件执行),保存当前的现场(PSW,中断屏蔽寄存器,通用寄存器,屏蔽字寄存器等值—由操作系统保存),当抢占的线程执行结束,然后将栈或者内存中存放的pc值压入PC(程序计数器),恢复现场,继续执行。

    分代年龄: 对象头里面的一个字段,当经过一次gc之后,未被清除,则分代年龄+1.

    本地方法区
    对于这个方法,底层的代码实现是c语言实现的,而不是java实现,当java执行到这个方法的时候,由底层的执行引擎去调用c语言的库函数,在windows系统中调用的文件类型为XXX.dll,有方法接口的具体实现。
    本地方法区的实例代码:
    在这里插入图片描述
    在compute()–栈帧中,局部变量表和操作数栈(存储在运行过程中产生的中间数据)的执行过程,具体指令为:

    在这里插入图片描述
    基本的操作就是,先为变量在局部变量表中开辟空间,然后1压入操作数栈,然后将操作数栈的数值压入给局部变量a,即变量a=1, 局部变量b也是一样,然后将a和b的值加载到操作数栈,通过指令iadd,从操作数栈中取出栈顶的两个数值进行相加,将相加的值放入栈顶,将10压入操作数栈,指令imul取出栈顶的两个元素相乘,值为3*10=30,即c=30,将30返回即可。
    栈的操作:后进先出

    打开cmd,输入命令:jvisualvm
    即将出现调试工具:会监控到jvm运行的所有线程情况。
    在这里插入图片描述
    后续内容在更新。

    展开全文
  • 深入理解jvm虚拟机

    2014-06-24 14:52:08
    jvm虚拟机深入讲解,理解jvm的核心原理,是学习jvm的原理的很好教科书
  • 认识JVM虚拟机

    2020-12-21 21:36:55
    JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 引入Java语言虚拟机后,Java语言在不同平台上...
  • 详细介绍了jvm虚拟机规范,很好 第一章引言 第二章 java概念 第三章 java虚拟机结构 第四章 class文件格式 第五章 常熟池解析 第六章 java虚拟机指令集 第七章 为java虚拟机编译 第八章 线程和锁 第九章 优化 第十章...
  • -heap : 打印jvm heap的情况,会列出堆的总体使用情况,还有新生代老生代的内存占用情况。 -histo: 打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。 -histo:live : 同上,但是只答应存活...

    -heap : 打印jvm heap的情况,会列出堆的总体使用情况,还有新生代老生代的内存占用情况。
    -histo: 打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。
    -histo:live : 同上,但是只答应存活对象的情况 
    -permstat: 打印permanent generation heap情况

    展开全文
  • JVM(Java虚拟机)一种用于计算设备的规范,可用不同的方式(软件或硬件)加以实现。接下来通过本文给大家简单介绍Java JVM虚拟机运行机制,感兴趣的朋友一起看看吧
  • jvm虚拟机-什么是jvm

    千次阅读 多人点赞 2016-12-30 17:23:39
    经过一段时间的研究深入理解java虚拟机后>>,才决定写一些关于jvm的文章,不为别的只为了同为技术的程序员们少走一些弯路,因为这本书第一遍读起来晦涩难懂,我也是查阅了大量的资料才渐渐的理解了什么意思。...
  • jvm虚拟机规范和入门资料jvm虚拟机规范和入门资料jvm虚拟机规范和入门资料jvm虚拟机规范和入门资料jvm虚拟机规范和入门资料jvm虚拟机规范和入门资料jvm虚拟机规范和入门资料jvm虚拟机规范和入门资料jvm虚拟机规范和...
  • 简述JVM虚拟机由哪几部分组成? 程序计数器 程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,可以理解为是当前线程的行号指示器。字节码解释器在工作时,会通过改变这个...
  • jvm虚拟机工作原理

    千次阅读 2018-05-31 15:23:23
    今天博客的正文,这一周都在研究这个虚拟机,找了一些相关资料,看了一些视频,大概知道一点点,小弟学时不多,有说的不对的地方,或者不详细的地方欢迎留言补充,交流学习。1.什么是虚拟机 联想到的问题,为什么说...
  • JVM 虚拟机栈详解

    千次阅读 2017-11-28 17:01:17
    当Java虚拟机运行程序时。每当一个新的线程被创建时。Java 虚拟机都会分配一个虚拟机栈,Java虚拟机栈是以帧为单位来保存线程的运行状态。Java栈只会有两种操作:以帧为单位...jvm会使用它来存储我们的形参,局部变量,
  • 主要介绍了jvm虚拟机栈的作用,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • Java JVM虚拟机学习的经典书籍

    千次阅读 2019-02-20 21:55:47
    1、深入理解Java虚拟机——JVM高级特性与最佳实践(第2版) 基于最新JDK1.7,围绕内存管理、执行子系统、程序编译与优化、高效并发等核心主题对JVM进行全面而深入的分析,深刻揭示JVM的工作原理。以实践为导向,...
  • 1. 课程聚焦Java性能调优的核心知识点,以真实场景项目实战为导向,循序渐进,深入浅出的了解JVM虚拟机,讲解Java这门使用广泛的编程语言,助你能够游刃有余地游走在这些技术之中。
  • 1. 深入理解JVM虚拟机(一):JDK、JRE、JVM的区别 在讲解 JVM 虚拟机知识之前,我们有必要先弄清它的概念。 很多程序员已经干了一段时间 Java 开发了依然不明白 JDK、JRE、JVM 的区别,现在我们就捋一捋: 概念...
  • JVM虚拟机的详细介绍1. 内存模型以及分区2. 堆里面的分区:Eden,survival (from+ to),老年代,各自的特点。3. GC 的两种判定方法4. SafePoint 是什么5. GC 的三种收集方法的优缺点6. JVM 内存分哪几个区,每个区...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 301,470
精华内容 120,588
关键字:

jvm虚拟机