jvm基础(1)

1.整型数和浮点型数的表示

  原码:第一位为符号位(0为正数,1为负数)。

  反码:符号位不动,源码取反。

  正数补码:和原码相同。

  负数补码:符号位不动,反码加1。

  例如5的二进制表示可以是00000101,-6的表示:原码10000110,反码11111001,补码11111010,-1的表示:10000001,反码11111110,补码11111111

  补码的好处:0的表示唯一,数的符号位可以同数值部分作为一个整体参与运算,可以直接做加法,减法运算可以用加法来实现,即用求和来代替求差。

  例如:0的表示:正数00000000,负数10000000。

     -6+5                -4+5

       11111010         11111100

+00000101       +00000101

= 11111111      = 00000001

  打印正数的二进制表示

int a=-6;
for(int i=0;i<32;i++){
	int t=(a & 0x80000000>>>i)>>>(31-i);
	System.out.print(t);
}

  IEEE754浮点数的表示格式:s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm

符号位(1)  指数位(8) 尾数(23)

          e全0 尾数附加位全0,否则尾数附加位为1

          s*m*2(e-127)

  例如:1 10000001 0100000000000000000000

  -1*2(129-127)*(20+2-2) = -5

  将单精度浮点数转成IEEE754二进制表示的代码示例:

package work.jvm;
public class ftob {
    public static final int BITS = 32;
    public static void main(String[] args) {
         int i;
         ftob ftb = new ftob();
         float f = -9f;
         System.out.println("float is:" + f);
         int[] b = ftb.printBinaryFloat(f);
         System.out.print("Binary is:");
         for(i = 0; i < BITS; i++){
             System.out.print(b[i]);
         }
    }
    public int[] printBinaryFloat(float f){
       int j;
       int r[] = new int[32];
       int temp = Float.floatToIntBits(f);
       for(j = BITS-1; j >= 0; --j){
           r[BITS-1-j] = ((temp>>j)&0x01);
       }
       return r;
    }
}

2.jvm运行机制

  JVM启动过程:

  

  JVM基本结构:

  

  (1)PC寄存器:每个线程拥有一个PC寄存器,在线程创建时创建,指向下一条指令的地址,执行本地方法时,PC的值为undefined。

  (2)方法区:保存装载的类信息,如i类型的常量池、字段和方法信息、方法字节码,通常和永久区(Perm)关联在一起。

  (3)java堆:和程序开发密切相关,应用系统对象都保存在Java堆中,所有线程共享Java堆,对分代GC来说,堆也是分代的,GC的主要工作区间。

  

  (4)java栈:线程私有,栈由一系列帧组成(因此Java栈也叫做帧栈),帧保存一个方法的局部变量、操作数栈、常量池指针,每一次方法调用创建一个帧,并压栈。

    栈上分配:小对象(一般几十个bytes),在没有逃逸的情况下,可以直接分配在栈上,直接分配在栈上,可以自动回收,减轻GC压力,大对象或者逃逸对象无法栈上分配。

  (5)堆、栈、方法区交互:

public class AppMain
//运行时, jvm 把appmain的信息都放入方法区
{
    public static void main(String[] args)
    //main 方法本身放入方法区。
    {
        Sample test1 = new Sample("测试1");
        //test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面
        Sample test2 = new  Sample("测试2");
        test1.printName(); test2.printName();
    }
}
public class Sample
//运行时, jvm 把appmain的信息都放入方法区
{
    private  name;
    //new Sample实例后,name引用放入栈区里,name对象放入堆里
    public Sample(String name)
    {
        this.name = name;
    }
    //print方法本身放入 方法区里。
    public void printName()
    {
        System.out.println(name);
    }
}

3.jvm配置参数

  (1)Trace跟踪参数 

  -verbose:gc

  -XX:+printGC

可以打印GC的简要信息

  -XX:+PrintGCDetails 打印GC详细信息

  -XX:+PrintGCTimeStamps 打印CG发生的时间戳

  -Xloggc:log/gc.log 指定GC log的位置,以文件输出

  -XX:+TraceClassLoading 监控类的加载

  -XX:+PrintClassHistogram 按下Ctrl+Break后,打印信息 分别显示:序号、实例数量、总大小、类型

  (2)堆分配参数

  -Xmx –Xms 指定最大堆和最小堆,例如:-Xmx20m -Xms5m

  -Xmn 设置新生代大小

  -XX:NewRatio 新生代(eden+2*s)和老年代(不包含永久区)的比值,比如4 表示新生代:老年代=1:4,即年轻代占堆的1/5。

  -XX:SurvivorRatio 设置两个Survivor区和eden的比,比如8表示 两个Survivor :eden=2:8,即一个Survivor占年轻代的1/10。

  -XX:+HeapDumpOnOutOfMemoryError,OOM时导出堆到文件。

  -XX:+HeapDumpPath 导出OOM的路径。

  -XX:OnOutOfMemoryError 在OOM时,执行一个脚本。例如:

    -XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p,其中printstack.bat里脚本为D:/tools/jdk1.7_40/bin/jstack -F %1 > D:/a.txt。

    当程序OOM时,在D:/a.txt中将会生成线程的dump

    也可以在OOM时,发送邮件,甚至是重启程序

  (3)栈分配参数

  -Xss 通常只有几百K,决定了函数调用的深度,每个线程都有独立的栈空间,局部变量、参数 分配在栈上。

  (4)永久区

  -XX:PermSize  -XX:MaxPermSize

  (5)堆分配参数建议

    根据实际事情调整新生代和幸存代的大小

    官方推荐新生代占堆的3/8

    幸存代占新生代的1/10

    在OOM时,记得Dump出堆,确保可以排查现场问题

4.GC算法

  (1)引用计数算法

  引用计数器的实现很简单,对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1。只要对象A的应用计数器的值为0,则对象A就不可能再被使用,就可以清除了。像python和actionscript用的就是引用计数算法。引用计数有两个问题:i引用和去引用伴随加法和减法,影响性能;ii很难处理循环引用。这个算法java并没有采用。

  (2)标记清除

  标记-清除算法是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。

  (3)标记压缩

  标记-压缩算法适合用于存活对象较多的场合,如老年代。它在标记-清除算法的基础上做了一些优化。和标记-清除算法一样,标记-压缩算法也首先需要从跟节点开始,对所有可达对象做一次标记。但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端。之后,清理边界外所有的空间。

  (4)复制算法

  与标记-清除算法相比,复制算法是一种相对高效的回收方法。不适用于存活对象较多的场合,如老年代。将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。年轻代的from和to两个区(也叫s1和s2)就是复制算法的两个区。

  gc可能引发stop the world(STW)现象。STW是Java中一种全局暂停的现象,这个时候所有Java代码停止运行,native代码可以执行,但不能和JVM交互。原因多半由GC引起,还有dump线程,死锁检查,堆dump也有可能引发STW。危害:i长时间(零点几秒到几十秒,甚至更长)服务停止,没有响应;ii遇到HA系统,可能引起主备切换,严重危害生产环境。

5.分代思想与可触及性

  分代思想:依据对象的存活周期进行分类,短命对象归为新生代,长命对象归为老年代。

  根据不同代的特点,选取合适的收集算法:

    少量对象存活,适合复制算法。

    大量对象存活,适合标记清理或者标记压缩。

  可触及性:

    可触及的:-从根节点可以触及到这个对象。

    可复活的:-旦所有引用被释放,就是可复活状态,因为在finalize()中可能复活该对象。

    不可触及的:-在finalize()后,可能会进入不可触及状态,不可触及的对象不可能复活,可以被回收。

6.GC参数

  (1)串行收集器。最古老,最稳定,

效率高,

可能会产生较长的停顿。

    参数:

-XX:+UseSerialGC

      –新生代、老年代使用串行回收

      –新生代复制算法

      –老年代标记-压缩

  

  (2)并行收集器

  

  ParNew收集器

    -XX:+UseParNewGC

    新生代并行,老年代串行

    Serial收集器新生代的并行版本

    复制算法

    多线程,需要多核支持

    -XX:ParallelGCThreads 限制线程数量

  Parallel收集器

    类似ParNew,新生代复制算法,老年代 标记-压缩,更加关注吞吐量。

    -XX:+UseParallelGC  使用Parallel收集器+ 老年代串行。

    -XX:+UseParallelOldGC  使用Parallel收集器+ 并行老年代。

    -XX:MaxGCPauseMills  最大停顿时间,单位毫秒,GC尽力保证回收时间不超过设定值。

    -XX:GCTimeRatio  0-100的取值范围,垃圾收集时间占总时间的比,默认99,即最大允许1%时间做GC。

  (3)CMS收集器

    Concurrent Mark Sweep 并发标记清除,这个并发的意思是与用户现场一起执行。

    标记-清除算法

    与标记-压缩相比,并发阶段会降低吞吐量

    老年代收集器(新生代使用ParNew)

    -XX:+UseConcMarkSweepGC

    -XX:+ UseCMSCompactAtFullCollection Full GC后,进行一次整理,整理过程是独占的,会引起停顿时间变长。

    -XX:+CMSFullGCsBeforeCompaction,设置进行几次Full GC后,进行一次碎片整理。

    -XX:ParallelCMSThreads,设定CMS的线程数量。

    CMS运行过程比较复杂,着重实现了标记的过程,可分为

      i.初始标记。根可以直接关联到的对象,速度快。

      ii.并发标记。(和用户线程一起)。主要标记过程,标记全部对象。

      iii.重新标记。由于并发标记时,用户线程依然运行,因此在正式清理前,再做修正。

      iv.并发清除(和用户线程一起)。基于标记结果,直接清理对象

    特点:

      尽可能降低停顿,会影响系统整体吞吐量和性能。比如,在用户线程运行过程中,分一半CPU去做GC,系统性能在GC阶段,反应速度就下降一半。

      清理不彻底,因为在清理阶段,用户线程还在运行,会产生新的垃圾,无法清理。

      因为和用户线程一起运行,不能在空间快满时再清理。-XX:CMSInitiatingOccupancyFraction设置触发GC的阈值,如果不幸内存预留空间不够,就会引起concurrent mode failure。

  (4)几个实例

   以32M堆启动tomcat

  set CATALINA_OPTS=-server -Xloggc:gc.log -XX:+PrintGCDetails -Xmx32M -Xms32M -XX:+HeapDumpOnOutOfMemoryError -XX:+UseSerialGC -XX:PermSize=32M

  以512M堆启动tomcat

  set CATALINA_OPTS=-Xmx512m -Xms64m -XX:MaxPermSize=32M  -Xloggc:gc.log -XX:+PrintGCDetails -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:ParallelGCThreads=4

  (5)最后汇总一下GC参数:

    -XX:+UseSerialGC:在新生代和老年代使用串行收集器

    -XX:SurvivorRatio:设置eden区大小和survivior区大小的比例

    -XX:NewRatio:新生代和老年代的比

    -XX:+UseParNewGC:在新生代使用并行收集器

    -XX:+UseParallelGC :新生代使用并行回收收集器

    -XX:+UseParallelOldGC:老年代使用并行回收收集器

    -XX:ParallelGCThreads:设置用于垃圾回收的线程数

    -XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器

    -XX:ParallelCMSThreads:设定CMS的线程数量

    -XX:CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发

    -XX:+UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片的整理

    -XX:CMSFullGCsBeforeCompaction:设定进行多少次CMS垃圾回收后,进行一次内存压缩

    -XX:+CMSClassUnloadingEnabled:允许对类元数据进行回收

    -XX:CMSInitiatingPermOccupancyFraction:当永久区占用率达到这一百分比时,启动CMS回收

    -XX:UseCMSInitiatingOccupancyOnly:表示只在到达阀值的时候,才进行CMS回收

这一篇文章先写到这里,下一篇继续^-^

  

  

时间: 2024-11-08 17:25:53

jvm基础(1)的相关文章

jvm基础理解

一.jvm运行时内存区域 包含堆,虚拟机栈,本地栈(调用native方法时用到),方法区(perm区),程序计数器. 假设32位操作系统,这时系统限制每个进程大小为2G.这样上述这些区域(对于本地栈及程序计数器来讲,是无法设置的,hotspot有提供-Xoss参数用于设置本地方法栈.但实际是无效的)可以用相应参数设置,共同划分全部2G内存. 注意还有一块直接内存,不属于JAVA运行时区域.但是它的空间用得太多的话,还是受限于物理内存和虚拟内存总大小,因此也会抛出OutOfMemory.典型的re

JVM基础:深入学习JVM堆与JVM栈(转)

JVM栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;JVM堆解决的是数据存储的问题,即数据怎么放.放在哪儿,另外JVM堆中存的是对象.JVM栈中存的是基本数据类型和JVM堆中对象的引用. JVM基础概念:JVM堆与JVM栈 数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型.基本类型的变量保存原始值,即:他代表的值就是数值本身;而引用类型的变量保存引用值."引用值"代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置. 基本类型

【转】JVM基础概念总结:数据类型、堆与栈

JVM基础概念总结:数据类型.堆与栈.基本类型与引用类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型.基本类型的变量保存原始值,即:他代表的值就是数值本身:而引用类型的变量保存引用值.“引用值”代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置. 基本类型包括:byte, short, int, long, char, float, double, Boolean, returnAddress 引用类型包括:类类型,接口类型和数组. 堆与栈 堆和栈是

关于Java面试知识点解析——JVM基础篇

跳槽时时刻刻都在发生,但是我建议大家跳槽之前,先想清楚为什么要跳槽.切不可跟风,看到同事一个个都走了,自己也盲目的开始面试起来(期间也没有准备充分),到底是因为技术原因(影响自己的发展,偏移自己规划的轨迹),还是钱给少了,不受重视. 准备不充分的面试,完全是浪费时间,更是对自己的不负责(如果title很高,当我没说).今天给大家分享下 Java面试知识点解析--JVM基础篇 1)Java 是如何实现跨平台的? 注意:跨平台的是 Java 程序,而不是 JVM.JVM 是用 C/C++ 开发的,是

JVM基础和调优(二)

主要讲述java虚拟机的内存体系结构 了解了JVM 的一些基础之后,我们来看看java虚拟机内存的体系结构,这个是理解JVM垃圾收集算法的前提,理解了内存结构我们才能够针对不同的部分根据我们的程序进行优化.前面已经说明了,java的堆和栈,但是只是局部的说了一下,没有在java内存体系中说明. 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成图形,所以只要你有耐心,仔细,认真,并发挥你的想象力

JVM基础和调优(一)

最近的项目中,出现了内存和性能的问题,需要优化,所以趁着这个机会,把自己关于java虚拟机的东整理一下,不对的地方,欢迎指出. 数据类型,因为在java的优化的过程中,检测到的数据类型一般比较的基础,毕竟复杂的数据类型就是有基础的组合而来的. Java虚拟机中,数据类型可以分为两类:基本类型和引用类型.基本类型的变量保存原始值,表示的是数据本身的值,是数据中的最基础的部分,一般包含: byte,short,int,long,char,float,double,Boolean,returnAddr

JVM基础01-内存分配

一.什么是JVM Java作为主流编程语言: 它摆脱了硬件的束缚,一处编写,处处运行: 它提供了一种相对安全的内存管理和访问机制,避免了大部分的内存泄露和指针越界问题: 它实现了热点代码的检测和运行时编译优化,这使得Java应用能够随着时间的推移而获取更高的性能: 结构严谨,API丰富 .... 上图就是JVM的物理结构图,什么是JVM? JVM是JAVA最核心的基础,一切的JAVA程序都依赖于JVM,而且依赖于JVM的语言并不仅仅是JAVA,还有其他的著名语言例如JRuby,Scala等等.而

[Java] Java 技术和 JVM 基础

Java 由 Sun 公司在 1995 首次发布,既是一门编程语言,也是一个计算平台. Java 运行时版本 Java Runtime Edition 当你下载 Java 完时候,你会得到一个 Java Runtime Time(JRE).JRE 由三部分组成 : JVM,Java 平台的核心类,支持 Java 平台的库.这三部分是执行 Java 应用运行的基础. Java 编程语言 Java 是一门面向对象的编程语言,包括以下特性: 平台独立 - Java 应用被编译成字节码存储在 .clas

jvm基础概念和参数

1.Trace跟踪参数 -verbose:gc -XX:+printGC -XX:+PrintGCDetails 打印GC详细信息 -XX:+PrintGCTimeStamps 打印CG发生的时间戳 -Xloggc:log/gc.log 指定GC log的位置,以文件输出 -XX:+PrintHeapAtGC 每次一次GC后,都打印堆信息 -XX:+TraceClassLoading 监控类的加载 -XX:+PrintClassHistogram 按下Ctrl+Break后,打印类的信息, 分别

JVM基础(5)-垃圾回收机制

一.对象引用的类型 Java 中的垃圾回收一般是在 Java 堆中进行,因为堆中几乎存放了 Java 中所有的对象实例.谈到 Java 堆中的垃圾回收,自然要谈到引用.在 JDK1.2 之前,Java 中的引用定义很很纯粹:如果 reference 类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用.但在 JDK1.2 之后,Java 对引用的概念进行了扩充,将其分为强引用(Strong Reference).软引用(Soft Reference).弱引用(Weak