java虚拟机(JVM)常用知识点整理

知识点整理:

  1. java运行时数据区域(内存模型)
      1. Enden、from survivor、to survivor
      2. 老年代:大对象、15轮、相同多
      3. 存放实例、实例变量、数组
    1. 方法区
      1. 类信息、常量池、静态变量
    2. 栈 私有
      1. 栈帧:
        1. 局部变量表:局部变量---基本数据、对象引用、返回地址类型
        2. 操作数栈:算数运行、递归时的参数传递
        3. 动态链接:指向常量池中的符号引用,运行期间转化为直接引用
        4. 方法返回地址:
          1. return正常出口---恢复上一个栈帧数据、返回值入操作数栈、调用程序计数器
          2. 异常出口:异常处理器
    3. 程序计数器:字节码指令的行号指示器、私有
    4. OOM:
      1. Java heap spacess:内存泄露【垃圾对象太多】、内存溢出
      2. PermGen space:类信息过多、常量过多
      3. stackOverflowerError:递归深度、死循环
  2. GC 可达性分析:栈、方法区静态、常量池引用对象
    1. gc机制:分代收集:新生代--复制、老年代--标记整理
    2. 垃圾收集器:Parallel Scavenge(old)吞吐量、CMS服务响应速度、G1
    3. gc触发:minor、full触发(空间分配担保)
    4. gc过程:引用链OopMap、安全点、安全区
  3. 对象内存 对象头、实例数据、对齐
    1. 访问定位:句柄、直接指针
    2. new对象过程
    3. 类加载过程
      1. 类加载器:双亲委派模型
      2. 触发时机:new、静态、反射、先加载父类

jvm的内存布局 

JVM内存结构主要有三大块:堆内存、方法区、栈

  • 堆内存是JVM中最大的一块,由年轻代和老年代组成,线程共享
    • 年轻代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下年轻代按照8:1:1的比例来分配;
  • 方法区存储类信息、常量池、静态变量等数据,线程共享
  • 栈分为java虚拟机栈、本地方法栈,主要用于方法的执行,线程私有

 

为什么两个幸存空间 From Survivor、To Survivor 解决碎片问题

引进了“幸存区”作用:

  1. 降低gc频率,如果活着的对象全部进入老年代,老年代很快被填满,Full GC 的频率大大增加
  2. 解决碎片问题
  3. Eden 空间快满时 Minor GC ,频率得以降低

缺点:两个 Survivor ,10%的空间浪费、复制对象开销

机制

  1. 如果对象在新生代 gc 之后任然存活,暂时进入幸存区;以后每过一次 gc ,对象年龄+1,直到某个设定的值15或直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中
  2. 把 Eden : From Survivor : To Survivor 空间大小设成 8 : 1 : 1 ,对象总是在 Eden 区出生, From Survivor 保存当前的幸存对象, To Survivor 为空。一次 gc 发生后: 
    1. Eden 区活着的对象 + From Survivor 存储的对象被复制到 To Survivor ; 
    2. 清空 Eden 和 From Survivor ; 
    3. 颠倒 From Survivor 和 To Survivor 的逻辑关系: From 变 To , To 变 From

 

介绍jvm每个区域的作用 堆、方法区、栈、程序计数器

Java堆(Heap)

  1. 虚拟机启动时创建,内存中最大的一块,线程共享
  2. 存放对象实例、数组、实例成员变量
  3. 垃圾收集器管理的主要区域,也被称做“GC堆”,逻辑上连续,一般采用分代收集算法

方法区(Method Area)

  1. 线程共享,存储已被虚拟机加载的,类加载器 加载的---
    1. 类信息:
    2. 常量池:静态常量池:编译期生成的字面量【final常量】和符号引用 ;运行时常量池:jvm虚拟机在完成类装载操作后,运行期间生成的新常量
    3. 静态变量、编译器编译后的静态变量数据
    4. 即时编译器编译后的代码
  2. 内存回收目标主要是常量池的回收和对类型的卸载 

 

常量池的好处

常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享

例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中

  1. 节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间
  2. 节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等

 

JVM栈(JVM Stacks)

Java虚拟机栈

  1. 线程私有,生命周期与线程相同
  2. 描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接(指向常量池)、方法返回地址等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程 
    1. 局部变量表:局部变量:方法参数和方法内部定义的变量,局部变量表所需的内存空间在编译期间完成分配;【随着方法的消失而消失】
      1. 编译期可知的基本数据类型(boolean、byte、char、short、int、float、long、double)
      2. 对象or数组引用(作为参数)(reference类型 指针指向,内存数据存在堆中,类型信息存储在方法区)
      3. 返回地址类型(指向了一条字节码指令的地址)
    2. 操作数栈:先入后出,初始为空,在方法的执行过程中加入数据: 算术运算、方法参数、方法返回值
    3. 动态连接:栈帧包含的一个指针:指向运行时常量池中,所属方法的符号引用,在运行期间将符号引用转化为直接引用称为动态链接
    4. 方法返回地址 两种方式退出:
      1. 正常完成出口:是执行引擎遇到一个return的字节码指令,恢复上层方法的局部变量表和操作数栈,把返回值压入调用者栈帧的操作数栈中,然后调用程序计数器执行后一条指令。
      2. 异常完成出口:方法执行过程中遇到了异常,异常没有在方法体内得到处理,返回地址由异常处理器确定

本地方法栈(Native Method Stacks)

本地方法栈则是为虚拟机使用到的Native本地方法服务

 

程序计数器(Program Counter Register)

  1. 线程私有,一块较小的内存空间
  2. 当前线程所执行的字节码指令的行号指示器
    1. 通过改变这个计数器的值来选取下一条字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成
  3. 每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响

可达性分析+分代收集+回收算法

可达性分析=引用链枚举 判断一个对象是否存活、GC对象的判定方法

判断一个对象是否存活有两种方法:

1.引用计数法 xxx

对象设置引用计数器,引用对象时,计数器加一;引用失效时,计数器就减一;为零时,垃圾回收

缺陷:无法解决循环引用问题,也就是说当对象A引用对象B,对象B又引用者对象A,引用计数器都不为零,无法垃圾回收

2.可达性算法(引用链法) 栈、方法区的引用对象

从一个被称为GC Roots的对象开始向下搜索,如果一个对象到GC Roots没有引用链相连时,则说明此对象不可用

  • 虚拟机栈中引用的对象
  • 本地方法栈JNI引用的对象
  • 方法区静态变量引用的对象
  • 方法区常量池引用的对象

当一个对象不可达GC Root时,这个对象并不会立马被回收,被真正的回收需要经历两次标记

可达性分析中没有与GC Root的引用链,此时第一次标记并且进行一次筛选,筛选的条件是是否有必要执行finalize()方法

若有必要执行finalize()方法,对象将会放在F-Queue队列中,虚拟机会触发一个Finalize()线程去执行,GC对处于F-Queue中的对象进行第二次被标记,这时,该对象将被移除”即将回收”集合,等待回收

 

HotSpot 基于安全点的引用链枚举 (GC)

  1. 准确式GC 快速完成GC Roots引用链枚举
    1. 引用链枚举时,应用OopMap数据结构,快速完成GC Roots引用链枚举
    2. OopMap:在类加载完成时,存储 :寄存器和栈的 <偏移量,数据及数据类型>;
  2. 安全点检测:程序有长时间执行特征 --- 方法调用、循环跳转、异常跳转时
    1. 仅需在安全点记录OopMap信息;每条指令生成OopMap,则空间成本太大;
    2. 程序执行时仅在安全点停下来GC
  3. 多线程的主动式中断,使得各个线程都跑到安全点再停顿
    1. 在安全点、创建的对象分配内存时 设置一个标志
    2. 各个线程执行时主动轮询该标志,若为真,则中断挂起
  4. 安全区域检测:代码中,引用关系不发生变化
    1. 线程没有分配CPU时间,无法跑到安全点,导致代码中,引用关系不发生变化
    2. GC时可忽略该标识自己处于安全区域的线程
    3. 要离开安全区域,需要收到系统已完成引用链枚举的信号

 

java垃圾回收机制

  1. 自动:不需要显示释放对象内存,虚拟机自行执行
  2. GC时间:在虚拟机空闲、堆内存不足时触发,低优先级垃圾回收线程
  3. GC对象:没任何引用的对象(可达性算法)
  4. 方式:minorGC fullgc

java中垃圾回收的方法有哪些

  1. 标记-清除:x
    1. 标记哪些要被回收的对象,然后统一回收
    2. 特点:
      1. 标记和清除的效率低;
      2. 产生大量不连续的内存碎片,GC频繁---以后程序在分配较大的对象时,由于没有充足的连续内存导致GC频繁
  1. 复制算法: 适合年轻代
    • 把 Eden : From Survivor : To Survivor 空间大小设成 8 : 1 : 1 ,对象总是在 Eden 区出生,若Eden区满,触发minor GC
    • 若GC后,存活的对象太多,to survivor内存不够时,通过分配担保机制复制到老年代;老年代 full gc
  1. 标记-整理 适合老年代
    1. 在清除对象的时候先将可回收对象移动到一端,然后清除掉端边界以外的对象
      1. 解决大量内存碎片问题
      2. 当对象存活率较高时,效率也不差
  1. 分代收集  综合
    1. 根据对象的生存周期,将堆分为新生代和老年代
      1. 在新生代中,对象生存期短,采用复制算法
      2. 老年代里的对象存活率较高,使用标记-整理 或者 标记-清除

5.G1收集器的可预测停顿

 

Jvm对象分配方案 分代机制 何时进入老年代

对象优先在Eden分配;Eden区没有足够空间时,发起一次MinorGC;

  1.  大对象直接进入老年代;

     通过 -XX:PretenureSizeThreshold参数设置;

  1.  长期存活的对象进入老年代:存活轮次多 15

    MinorGC一次还存活在Survivor中,年龄+1; 通过 -XX:MaxTenuringThreshold参数设置;

  1.  年龄相同的大于一半,动态对象年龄判别:

    在survivor中年龄相同的所有对象大小总和大于 survivor 一半,年龄大于或等于该年龄的对象进入老年代;防止survivor满

  1.  空间(检测)分配担保机制:fullgc前 需要比较两次

每次MinorGC之前,会检查老年代最大连续可用空间是否大于 新生代所有对象的总空间,大于则表示安全,MinorGC;

    如果小于:(JDK 6U24不再检查HandlePromotionFailure,一定会冒险)

    检查HandlePromotionFailure 为 true ,允许冒险,历次晋升到老年代的对象平均大小与本次进入的对象大小比较,若历次大 MinorGC,若小 FullGC;

    HandlePromotionFailure 为 false,直接进行FullGC;

 

简述minor和fullgc,minorGC以及FullGC触发条件

  1. 新生代进行一次垃圾清理,被称为minorGC
  2. 老年代进行一次垃圾清理,被称为fullGC或者majorGC。速度一般较慢
  3. 大多数新生对象生命周期很短,所以MinorGC通常很频繁,回收速度也较快
  4. 降低MinorGC的频率、减少fullGC的次数

触发条件:

MinorGC:Eden区满时触发MinorGC;FullGC也会伴随有MinorGC;

FullGC:a. 老年代不够分配时,触发FullGC;

b. 空间(检测)分配担保机制:MinorGC触发前,比较老年代的剩余空间和新生代所有对象大小,老年代小,且不允许冒险,则fullgc

允许冒险,继续比较对象历次平均大小与本次进入老年代的大小,若本次大,则FullGC;

为什么要担保:每次minorgc,新生代年龄满15的会进入老年代,如果新生代全部对象都一起满15会导致老年代不够放

    c. 手动调用System.gc(),提醒JVM FullGC,但不可控;

 

栈溢出、堆溢出、内存溢出的原因

栈溢出的原因

  • 递归调用
  • 大量循环、死循环
  • 函数体内局部变量数组过大

内存溢出的原因是什么

  1. JVM没有及时回收,堆内存泄露
  2. 循环或递归中大量的new对象,堆溢出
  3. 静态变量大、类加载过多,类信息、方法区溢出
  4. 函数体内的数组过大,栈溢出
  5. 递归或无限递归,栈溢出

oom类型

导致的原因

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用

内存泄漏 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,最终会导致out of memory

1,Java Heap 溢出 

堆 存放对象实例和数组,线程共享;

  1. 内存不够:实例过多、数组过大、大量的new对象;集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
  2. 内存泄露:静态集合类引起内存泄露;各种连接没有关闭;单例对象持有外部对象的引用

 

一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess  

 

先分清是内存泄漏还是内存溢出

内存泄漏

通过工具查看泄漏对象到GC Roots的引用链,找到泄漏对象与GC Roots相关联路径, 

内存溢出

检查虚拟机的参数(-Xmx与-Xms)的设置是否适当 ;

通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转存快照进行分析,确认内存中的对象是否是必要的

2, 方法区溢出 运行时常量池溢出 

常量池溢出;

加载到方法区的类过多;类信息过多:同一个类文件被不同的类加载器重复加载

用于存储已被JVM加载的类信息、常量池、静态变量等。编译器编译后的代码,线程共享

异常信息:java.lang.OutOfMemoryError:PermGen space 

-XX:PermSize和-XX:MaxPermSize 设置方法区的大小

3, 虚拟机栈和本地方法栈溢出 

递归太深、死循环导致栈帧创建过多

线程请求的栈深度大于虚拟机允许的最大深度,抛出StackOverflowError异常 

在扩展栈时无法申请到足够的内存,则抛出OutOfMemoryError异常 

栈的大小越大,可分配的线程数就越少

 

4, 本机直接内存溢出

java.lang.OutOfMemoryError

-XX:MaxDirectMemorySize指定,默认和Java堆最大值一样

 

垃圾收集器 3类

1.吞吐量优先

Parallel Scavenge[ˈskævɪndʒ] 新生代 复制算法

parallel Old 老年代 标记-整理

2.重视服务响应速度,最短回收停顿时间

Parallel Scavenge[ˈskævɪndʒ] 新生代 复制算法

CMS(Concurrent Mark Sweep) 老年代 并发的标记-清除

  1. 初始标记(CMS initial mark)S
  2. 并发标记(CMS concurrent mark)
  3. 重新标记(CMS remark) S
  4. 并发清除(CMS concurrent sweep)

 

初始标记、重新标记:这两个步骤仍然需要“Stop The World”【所有线程停止工作】

  1. 初始标记仅仅只是标记一下GC Roots能直接关联到的对象【栈、方法区】,速度很快,要“Stop The World”
  2. 并发标记阶段就是进行GC Roots Tracing【引用链跟踪过程】的过程,刚才产生的集合中标记出存活对象
  3. 重新标记阶段则是为了修正并发标记期间,因用户程序继续运作,而导致标记产生变动的 部分对象的标记记录,要”Stop The World“
    1. 比初始标记阶段稍长一些,但远比并发标记的时间短
  4. 并发清理回收所有的垃圾对象,由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作

缺点:

  1. CPU资源敏感(需要并发)
  2. 无法处理浮动垃圾(边并发GC边产生垃圾)
    1. 在默认设置下,CMS收集器在老年代使用了68%的空间后就会被激活
    2. 要是CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”失败【运行时模式错误】
  3. 大量空间碎片(需要碎片整理)
    1. CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开关参数,用于在“享受”完Full GC服务之后额外免费附送一个碎片整理过程

3.面向服务器端应用,低停顿

G1收集器

  1. 并发,边GC边执行代码
  2. 分代收集:单个收集器,即可管理不同存活时间的对象
  3. 并发标记-整理算法,无空间碎片
  4. 可预测的停顿:可设定在长度为M毫秒内,垃圾收集时间不超过N毫秒
    1. 实现方式:将堆划分为相等的region,设置一个价值标记,进行跟踪;优先回收价值最大的region
    2. 价值标记:回收所获得的空间大小和所需时间的经验值,用优先队列维护

 

初始标记 GC Roots能直接关联到的对象 Stop the world

并发标记 从GC root开始对堆中的对象进行可达性分析、找出存活对象

最终标记 修正在并发标记其间,用户程序继续运行产生变动的标记记录 S

筛选回收 对各个region回收价值和成本进行排序,根据用户期望停顿时间进行回收 【S,或者并发回收】

 

类加载器

通过类的全限定名获取该类的二进制字节流

主要有一下四种类加载器:

1. 启动类加载器(Bootstrap ClassLoader):加载Java核心类库[JAVA_HOME/lib];无法被直接饮用,若自定义类加载器时需要委派给启动类加载器,则直接使用null代替

2. 扩展类加载器(extensions class loader): 加载Java 的扩展库[JAVA_HOME/lib/ext];发者可直接使用扩展类加载器

3. 系统类加载器(system class loader):根据类路径(CLASSPATH)加载 Java 应用的类。ClassLoader.getSystemClassLoader()来获取

4. 用户自定义类加载器,继承 java.lang.ClassLoader类的方式实现

 

类加载器的双亲委派模型

层次关系:启动类加载器--扩展类加载器---系统类加载器---自定义类加载器

  1. 某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归;若父类加载不了,再返回由子类加载
  2. 优点:
    1. 使类加载器具有带优先级的层次关系;
    2. 保证java程序稳定运行
  3. 父子关系采用组合而非继承的方式实现

 

OSGI破坏双亲委派模型

  1. 实现代码热替换、模块热部署,想电脑插拔鼠键一样
  2. OSGI实现自定义类加载机制,每一个程序模块Bundle都有自己的类加载器,更换Bundle时连同类加载器一起替换
  3. 类加载模型为复杂的网络结构,当收到类加载请求时,OSGI根据网络结构,实现自己的类搜索顺序

 

类加载过程 【加载、验证、准备、解析、初始化】

1.加载 3

  1. 通过一个类的全限定名来获取定义此类的二进制字节流(Class文件、网络、动态生成、数据库等);
  2. 转化为方法区的运行时数据结构;【方法区没有所以才加载类、有了就拷贝】

连接阶段包括:验证、准备、解析

2.验证 信息

验证字节流中的信息,符合当前虚拟机要求,不危害虚拟机安全

4个阶段的检验动作:

  1. 文件格式验证:字节流是否符合Class文件格式规范
  2. 元数据验证:语义分析,保证字节流描述的信息符合Java语言规范
  3. 字节码验证:数据流和控制流分析,确定程序语义是合法的
  4. 符号引用验证:确保解析动作能正确执行

 

3.准备 分配初值 方法区中

  1. 方法区中为静态变量分配内存,并设置初始 0 值
  2. 为final常量赋 初始值(程序定义的值)

不包括实例变量,实例变量在对象实例化时随着对象一起分配在堆中

例:初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为:

1

public static int value=123;

那变量value在准备阶段过后的初始值为0而不是123.把value赋值为123的动作将在初始化阶段才会执行。

特殊情况:public static final int value=123,final修饰的常量,始化为123

4.解析 符号引用->直接引用

  1. 虚拟机将方法区【常量池内】【符号引用】 -替换为- 【直接引用】;多态实现
    1. 符号引用以一组 符号来描述所引用的目标;
    2. 直接引用可以是 直接指向目标的指针

解析动作主要针对类、接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

5.初始化 静态变量、静态代码块、方法区存储类信息

  1. 为静态变量赋程序中的值
  2. 执行static代码块
    1. static代码块只有jvm能够调用
    2. 多线程仅允许一个线程初始化操作,其余线程等待
  3. 类的加载顺序是先加载父类后加载子类
  4. 方法区会存储当前类信息:
    1. 包括类的静态变量、实例变量定义、父类的类信息引用
    2. 类初始化代码(定义静态变量时的赋值语句 和 静态初始化代码块)
    3. 实例初始化代码(定义实例变量时的赋值语句:实例方法、构造方法)

 

6.接new过程的堆中分配内存

 

触发条件

(1) 创建new类实例 (2) 访问静态变量、对静态变量赋值 (3) 调用静态方法 (4) 反射(如Class.forName(“com.shengsiyuan.Test”)) (5) 加载子类前,先加载父类 (6) Java虚拟机启动时被标明为启动类的类(Java Test),直接使用java.exe命令来运行某个主类

 

new一个对象创建的过程 

包括5个步骤:类加载检查过程、堆分配内存、内存初始化为零、对象头设置、执行对象实例方法

  1. 类加载检查过程 检查是否能在常量池中定位到类的符号引用,无则执行类加载
    1. “new” 操作转换为Class文件中“new”字节码指令
    2. 检查指令参数是否能在常量池中定位到一个类的符号引用:
      1. 如果不能定位到,执行类加载过程;【见上面】
      2. 如果能定位到,则在堆中创建一个对象的拷贝
  2. 堆中分配内存 类加载后,Java堆分配内存
    1. 类加载完成后确定对象所需内存的大小,从Java堆分配
  3. 对象实例变量初始化,零值、null值
    1. 保证实例变量不赋初始值,也可以使用;
  4. 对象头设置
    1. 主要设置对象头信息,包括偏向锁模式、对象的哈希码、对象的GC分代年龄等(详见下节);
  5. 执行对象实例方法
    1. 实例变量赋值
    2. 构造方法
  1. memory = allocate();   //1:分配对象的内存空间  
  2. ctorInstance(memory);  //2:初始化对象  
  3. instance = memory;     //3:设置instance指向刚分配的内存地址  

 

2.3步可能会被指令重排序优化,导致单例模式出错、加volatile

 

将方法区内的 将实例变量的定义 拷贝到堆,按照程序中定义的赋值

初始化顺序是先初始化父类再初始化子类,初始化时先执行静态代码块,然后是构造方法

 

String s = new String(“xyz”);产生几个对象

先去方法区常量池中查找是否已经有了”s”对象

  1. 如果没有则在常量池中创建一个“ s ”对象,然后堆中再创建一个常量池中此”s”对象的拷贝对象;2个对象
  2. 否则,只需要在堆中创建一个“ s ”对象

 

自定义类加载器

需要继承java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,即指明如何获取类的字节码流。

如果要符合双亲委派规范,则重写findClass方法(用户自定义类加载逻辑);要破坏的话,重写loadClass方法(双亲委派的具体逻辑实现)

 

对象的内存布局:对象头、实例数据、对齐填充

  1. 对象头信息
    1. Mark Word 6个: hash码、GC年龄、锁状态标识、持有的锁owner、偏向锁线程ID、偏向锁时间戳
    2. 类型指针 判断对象属于哪个类的实例,指向所属类的指针,
  2. 实例数据 存储真正有效数据
    1. 字段的分配策略:相同宽度的字段总是被分配到一起,便于之后取数据;
    2. 父类定义的变量会出现在子类前面
  3. 对齐填充 占位符的作用,非必须

 

对象实例数据的访问定位:

1.使用句柄地址:二次定位

java堆中将会划出内存作为句柄池,reference存储句柄地址,再通过句柄中的实例数据指针,查找堆中对象实例数据

优点:对象被移动时,只改变实例数据指针(垃圾回收时)

2.直接指针访问对象实例数据,reference中存储的就是对象堆中的实例数据地址【类型数据都是在方法区】

优点:只进行了一次指针定位,节省了时间,而这也是HotSpot采用的实现方式;由于对象访问比较频繁,这个较好

 

类型数据都是通过指针二次查找,存储在方法区

JVM优化 内存、收集器、工具

参数调优

java堆栈大小设置相关

-Xms :设置Java堆栈的初始化大小

-Xmx :设置最大的java堆大小

-XX:PermSize and MaxPermSize :设置持久带的大小

-XX:NewRatio :设置年轻代和老年代的比值

-XX:NewSize :设置年轻代的大小

打印垃圾回收信息

verbose:gc :记录GC运行以及运行时间,一般用来查看GC是否有瓶颈

-XX:+PrintGCDetails :记录GC运行时的详细数据信息,包括新生占用的内存大小及消耗时间

-XX:-PrintGCTimeStamps :打印收集的时间戳

垃圾集器配置

-XX:+UseParallelGC :使用并行垃圾收集器

-XX:ParallelGCThreads=N,设置并行垃圾回收的线程数,此值可以设置与机器处理机数量一致(有建议core+3/4);

-XX:-UseConcMarkSweepGC :使用CMS 并发标志扫描收集器

-XX:-UseSerialGC :使用串行垃圾收集器

配置日志文件

-Xloggc:filename :设置GC记录的文件

-XX:+UseGCLogFileRotation :启用GC日志文件的自动转储

-XX:GCLogFileSize=1M :控制GC日志文件的大小

类加载和跟踪类加载和卸载的信息【诊断内存泄露】

-XX:+TraceClassLoading :跟踪类加载的信息

-XX:+TraceClassUnloading :跟踪类卸载的信息

JVM性能调优工具 VisualVM、BTrace、Yslow

  1. jps(Java Virtual Machine Process Status Tool)
    1. 主要用来输出JVM中运行的进程状态信息
  2.  jstack(Java Stack Trace)
    1. 主要用来查看某个Java进程内的线程堆栈信息。语法格式如下:
  3. jmap(Java Memory Map)
    1. jmap用来查看堆内存使用状况,一般结合jhat使用
  4. jhat(Java Heap Analysis Tool)
    1. 用于对Java 堆进行离线分析的工具,它可以对不同虚拟机中导出的heap信息文件进行分析
  5. jstat(Java Virtual Machine Statistics Monitoring Tool)
    1. Jstat用于监控基于HotSpot的JVM,对其堆的使用情况进行实时的命令行的统计,使用jstat我们可以对指定的JVM做如下监控:
  6. jconsole
    1. 一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM。用java写的GUI程序,用来监控VM,并可监控远程的VM,非常易用,而且功能非常强。命令行里打 jconsole,选则进程就可以了
  7. GC日志:内存回收的详细情况,频繁程度、GC导致应用停止的时间,GC的原因

 

java GC延迟问题 GC优化 原因及解决办法

  • 详细的 GC 日志,查看 GC 日志中是否出现了上述的典型内存异常问题(promotion failed, concurrent mode failure)
  • 借助 Linux 平台下的 iostat、vmstat、netstat、mpstat 等命令监控系统情况
  • 使用 VisualVM、GCHisto 这个 GC 图形用户界面工具,可以统计出 Minor GC 及 Full GC 频率及时长分布,可参考:http://blog.csdn.net/wenniuwuren/article/details/50760259
  • 如果程序没问题,参数调了几次还是不能解决,可能说明流量太大,需要加机器把压力分散到更多 JVM 上

 

性能测试:AJmeter

SpringMVC流程

 

账户A转到账户B,什么流程 rollback

脏读,不可重复读,幻读

介绍一下hadoop mapreduce能解决什么问题

hadoop 海量文档计算重复最多的词

你可能感兴趣的:(java基础)