>>分享Java编程技术,对《Java面向对象编程》等书籍提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 16412 个阅读者 刷新本主题
 * 贴子主题:  搞定这24道JVM面试题,要价30k都有底气 回复文章 点赞(0)  收藏  
作者:Jacky    发表时间:2020-12-27 02:57:49     消息  查看  搜索  好友  邮件  复制  引用

  

  1.什么是 JVM

  JVM的全称是 「Java Virtual Machine」,也就是我们耳熟能详的 Java 虚拟机。它能识别 .class后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作。

C++开发出来的程序,编译成二进制文件后,就可以直接执行了,操作系统是能够识别的。

但是咱们的Java程序就不一样了,使用 javac命令编译出来的的.class文件之后,操作系统是不能识别的,需要对应 JVM去做一个转换后,操作系统才能识别。

  2.说说 JDK、 JRE、 JVM的关系

  JDK是Sun公司(已被Oracle收购)针对Java开发员的软件开发工具包。自从Java推出以来, JDK已经成为使用最广泛的Java SDK(Software development kit)。

  JRE全称Java Runtime Environment,是运行基于Java语言编写的程序所不可缺少的运行环境。也是通过它,Java的开发者才得以将自己开发的程序发布到用户手中,让用户使用。

  JVM就是 Java 虚拟机,它能识别 .class后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作。

  JDK中包含 JRE,也包括 JDK,而 JRE也包括 JDK。

范围关系: JDK> JRE> JVM。

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  3.获取class文件有哪些方式?

  1. 从本地文件系统中加载.class文件
  2. 从jar包中或者war包中加载.class文件
  3. 通过网络或者从数据库中加载.class文件
  4. 把一个Java源文件动态编译,并加载,加载进来后就,系统为这个.class文件生成一个对应的Class对象。

  4.生成Class对象的有哪些方式?

1.对象获取。调用person类的父类方法 getClaass();

2.类名获取。每个类型(包括基本类型和引用)都有一个静态属性,class;

3.Class类的静态方法获取。forName("字符串的类名")写全名,要带包名。(包名.类名)

  5.类加载器有哪些?

   Bootstrap ClassLoader

负责加载 $JAVA_HOME中 jre/lib/rt.jar里所有的class或 Xbootclassoath选项指定的jar包。由C++实现,不是 ClassLoader子类。

   Extension ClassLoader

负责加载 Java平台中扩展功能的一些jar包,包括$JAVA_HOME中 jre/lib/*.jar或 -Djava.ext.dirs指定目录下的jar包。

   App ClassLoader

负责加载 classpath中指定的jar包及 Djava.class.path所指定目录下的类和jar包。

   Custom ClassLoader

通过 java.lang.ClassLoader的子类自定义加载class,属于应用程序根据自身需要自定义的 ClassLoader,如 tomcat、 jboss都会根据 j2ee规范自行实现 ClassLoader。

  6.如何自定义类加载器

用户根据需求自己定义的。需要继承自 ClassLoader,重写方法 findClass()。

如果想要编写自己的类加载器,只需要两步:
  • 继承 ClassLoader类
  • 覆盖 findClass(String className)方法
  **ClassLoader**超类的 loadClass方法用于将类的加载操作委托给其父类加载器去进行,只有当该类尚未加载并且父类加载器也无法加载该类时,才调用 findClass方法。如果要实现该方法,必须做到以下几点:

1.为来自本地文件系统或者其他来源的类加载其字节码。2.调用 ClassLoader超类的 defineClass方法,向虚拟机提供字节码。

  7.如何设置Java虚拟机栈的大小呢?

可以使用虚拟机参数-Xss 选项来设置线程的最大栈空间,栈的大小直接决定了函数调用的最大可达深度;

  -Xss size

  8.方法区、堆、栈之间到底有什么关系?

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  栈指向堆

如果在栈帧中有一个变量,类型为引用类型,比如

   packagecom.tian.my_code.test;

public  class JvmCodeDemo{
  publicObject testGC (){
intop1= 10;
intop2= 3;
Objectobj= newObject();
Objectresult=obj;
returnresult;
}
}

这时候就是典型的栈中元素obj指向堆中的Object对象,result的指向和obj的指向为同一个对象。

          使用命令

  javac -g:vars JvmCodeDemo.java

进行编译,然后再使用

  javap -v JvmCodeDemo.class >log.txt

然后打开 log.txt文件    

  方法区指向堆

方法区中会存放静态变量,常量等数据。

如果是下面这种情况,就是典型的方法区中元素指向堆中的对象。【 「红线」】

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  堆指向方法区

方法区中会包含类的信息,对象保存再堆中,创建一个对象的前提是有对应的类信息,这个类信息就在方法区中。

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  9.Java对象内存是如何布局的?

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

一个Java对象在内存中包括3个部分:对象头、实例数据和对齐填充。

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  10.如何理解Minor/Major/Full GC?

还可能问你:请说一下Minor/Major/Full GC分别发送在哪个区域。
   Minor GC:发生在年轻代的 GC Major GC:发生在老年代的 GC。Full GC:新生代+老年代,比如 Metaspace 区引起年轻代和老年代的回收。

  11.能够触发条件 Full GC 有哪些?

1)调用System.gc时,系统建议执行Full GC,但是不必然执行;

2)老年代空间不足;

3)方法去空间不足;

4)通过Minor GC后进入老年代的平均大小 > 老年代的可用内存;

5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小。即老年代无法存放下新年代过度到老年代的对象的时候,会触发Full GC。

  12.为什么需要Survivor区

如果没有Survivor,Eden区每进行一次Minor GC ,并且没有年龄限制的话, 存活的对象就会被送到老年代。这样一来,老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。

执行时间长有什么坏处频发的Full GC消耗的时间很长,会影响大型程序的执行和响应速度。

可能你会说,那就对老年代的空间进行增加或者较少咯。

假如增加老年代空间,更多存活对象才能填满老年代。虽然降低Full GC频率,但是随着老年代空间加大,一旦发生Full GC,执行所需要的时间更长。

假如减少老年代空间,虽然Full GC所需时间减少,但是老年代很快被存活对象填满,Full GC频率增加。

所以Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16 次Minor GC还能在新生代中存活的对象,才会被送到老年代。

  13.为什么需要两个大小一样的Survivor区?

最大的好处就是解决了碎片化。

假设现在只有一个Survivor区,我们来模拟一下流程:

刚刚新建的对象在Eden中,一旦Eden满了,触发一次Minor GC,Eden中的存活对象就会被移动到Survivor区。这样继续循 环下去,下一次Eden满了的时候,问题来了,此时进行Minor GC,Eden和Survivor各有一些存活对象,如果此时把Eden区的 存活对象硬放到Survivor区,很明显这两部分对象所占有的内存是不连续的,也就导致了内存碎片化。

永远有一个Survivor space是空的,另一个非空的Survivor space无碎片。

  14.新生代中Eden:S1:S2为什么是8:1:1?

新生代中的可用内存:复制算法用来担保的内存为9:1,所以只会造成 10% 的空间浪费。可用内存中 Eden:S1区为8:1 即新生代中 Eden:S1:S2= 8:1:1

这个比例,是由参数 -XX:SurvivorRatio进行配置的(默认为 8)。

  15.如何判断对象已死?

  引用计数法

给对象添加一个引用计数器,每当一个地方引用它object时技术加1,引用失去以后就减1,计数为0说明不再引用
  • 优点:实现简单,判定效率高
  • 缺点:无法解决对象相互循环引用的问题,对象A中引用了对象B,对象B中引用对象A。
点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

   public  class A{
publicBb;
}
public  class B{
publicCc;
}
public  class C{
publicAa;
}
public  class Test{

  private void test (){
Aa= newA();
Bb= newB();
Cc= newC();

a.b=b;
b.c=c;
c.a=a;
}
}

  可达性分析算法

当一个对象到 GC Roots没有引用链相连,即就是 GC Roots到这个对象不可达时,证明对象不可用。

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  GC Roots种类:
   Java 线程中,当前所有正在被调用的方法的引用类型参数、局部变量、临时值等。也就是与我们栈帧相关的各种引用。所有当前被加载的 Java 类。Java 类的引用类型静态变量。运行时常量池里的引用类型常量(String 或 Class 类型)。JVM 内部数据结构的一些引用,比如 sun.jvm.hotspot.memory.Universe 类。用于同步的监控对象,比如调用了对象的 wait() 方法。
   public  class Test{
  private void test (Cc){
Aa= newA();
Bb= newB();
a.b=b;
//这里的a/b/c都是GC Root;
}
}

  16.对象的有几种引用类型?

  •   强引用: User user=new User();我们开发中使用最多的对象引用方式。

    特点:我们平常典型编码 Object obj = new Object()中的obj就是强引用。

    通过关键字new创建的对象所关联的引用就是强引用。

    当 JVM内存空间不足, JVM宁愿抛出 OutOfMemoryError运行时错误( OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。

    对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略。
  •   软引用: SoftReference<Object> object=new SoftReference<Object>(new Object());

    特点:软引用通过 SoftReference类实现。软引用的生命周期比强引用短一些。只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象:即JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续,我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。

    应用场景:软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存
  •   弱引用: WeakReference<Object> object=new WeakReference<Object> (new Object(); ThreadLocal中有使用.

    弱引用通过 WeakReference类实现。弱引用的生命周期比软引用短。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。

    弱引用可以和一个引用队列( ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。应用场景:弱应用同样可用于内存敏感的缓存。
  •   虚引用:几乎没见过使用, ReferenceQueue 、PhantomReference

  17.finalize方法有了解吗?

这个方法就有点类似:某个人被判了死刑,但是不一定会死。

即使在可达性分析算法中不可达的对象,也并非一定是“非死不可”的,这时候他们暂时处于“缓刑”阶段,真正宣告一个对象死亡至少要经历两个阶段:

1、如果对象在可达性分析算法中不可达,那么它会被第一次标记并进行一次刷选,刷选的条件是是否需要执行finalize()方法(当对象没有覆盖finalize()或者finalize()方法已经执行过了(对象的此方法只会执行一次)),虚拟机将这两种情况都会视为没有必要执行)。

2、如果这个对象有必要执行finalize()方法会将其放入F-Queue队列中,稍后GC将对F-Queue队列进行第二次标记,如果在重写finalize()方法中将对象自己赋值给某个类变量或者对象的成员变量,那么第二次标记时候就会将它移出“即将回收”的集合。

  18.垃圾回收算法有哪些?

  标记-清除算法

第一步:就是找出活跃的对象。我们反复强调 GC 过程是逆向的, 根据 GC Roots 遍历所有的可达对象,这个过程,就叫作标记。

第二部:除了上面标记出来的对象以外,其余的都清楚掉。
  • 缺点:标记和清除效率不高,标记和清除之后会产生大量不连续的内存碎片
点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  复制算法

新生代使用,新生代分中 Eden:S0:S1= 8:1:1,其中后面的1:1就是用来复制的。

当其中一块内存使用完了,就将还存活的对象复制到另外一块上面,然后把已经使用过的内存空间一次 清除掉。

          一般对象分配都是进入新生代的eden区,如果 Minor GC还存活则进入 S0区, S0和 S1不断对象进行复制。对象存活年龄最大默认是15,大对象进来可能因为新生代不存在连续空间,所以会直接接入老年代。任何使用都有新生代的10%是空着的。
  • 缺点:对象存活率高时,复制效率会较低,浪费内存。

  标记整理算法

它的主要思路,就是移动所有存活的对象,且按照内存地址顺序依次排列,然后将末端内存地址以后的内存全部回收。但是需要注意,这只是一个理想状态。对象的引用关系一般都是非常复杂的,我们这里不对具体的算法进行描述。我们只需要了解,从效率上来说,一般整理算法是要低于复制算法的。这个算法是规避了内存碎片和内存浪费。

让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

          从上面的三个算法来看,其实没有绝对最好的回收算法,只有最适合的算法。

  19.新生代有哪些垃圾收集器?

  serial

Serial收集器是最基本、发展历史最悠久的收集器,曾经(在JDK1.3.1之前)是虚拟机新生代收集的唯一选择。

它是一种单线程收集器,不仅仅意味着它只会使用一个CPU或者一条收集线程去完成垃圾收集工作,更重要的是其在进行垃圾收集的时候需要暂停其他线程。
   优点:简单高效,拥有很高的单线程收集效率 缺点:收集过程需要暂停所有线程 算法:复制算法 应用:Client模式下的默认新生代收集器
      收集过程:    

  ParNew

可以把这个收集器理解为Serial收集器的多线程版本。
   优点:在多CPU时,比Serial效率高。缺点:收集过程暂停所有应用程序线程,单CPU时比Serial效率差。算法:复制算法 应用:运行在Server模式下的虚拟机中首选的新生代收集器
      收集过程:    

  Parallel Scanvenge

Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集 器,看上去和 ParNew一样,但是 Parallel Scanvenge更关注 系统的吞吐量 ;
   吞吐量 = 运行用户代码的时间 / (运行用户代码的时间 + 垃圾收集时间)

比如虚拟机总共运行了120秒,垃圾收集时间用了1秒,吞吐量=(120-1)/120=99.167%。

若吞吐量越大,意味着垃圾收集的时间越短,则用户代码可以充分利用CPU资源,尽快完成程序的运算任务。
可设置参数:

  -XX:MaxGCPauseMillis控制最大的垃圾收集停顿时间,
-XX:GC Time Ratio直接设置吞吐量的大小。


  20.老年代有哪些垃圾收集器?

  CMS=Concurrent Mark Sweep

  「特点」:最短回收停顿时间,

  「回收算法」:标记-清除

  「回收步骤」:
  1. 初始标记:标记 GC Roots直接关联的对象,速度快
  2. 并发标记: GC Roots Tracing过程,耗时长,与用户进程并发工作
  3. 重新标记:修正并发标记期间用户进程运行而产生变化的标记,好事比初始标记长,但是远远小于并发标记
  4. 表发清除:清除标记的对象
  「缺点」:对CPU资源非常敏感,CPU少于4个时,CMS岁用户程序的影响可能变得很大,有此虚拟机提供了“增量式并发收集器”;无法回收浮动垃圾;采用标记清除算法会产生内存碎片,不过可以通过参数开启内存碎片的合并整理。

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

收集过程:

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

  serial old

Serial Old收集器是Serial收集器的老年代版本,也是一个单线程收集器,不同的是采用"标记-整理算 法",运行过程和Serial收集器一样。

  「适用场景」: JDK1.5前与 Parallel Scanvenge配合使用,作为 CMS的后备预案;

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

收集过程:    

  Parallel old

Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和"标记-整理算法"进行垃圾 回收,吞吐量优先;

  「回收算法」:标记-整理

  「适用场景」:为了替代 serial old与 Parallel Scanvenge配合使用

          收集过程:    

  G1=Garbage first

从 JDK9 开始, JVM的默认垃圾回收器就从 Parallel GC调整为 G1,并且开始全面废除 CMS。

限制或者减少 GC 停顿时间相比系统吞吐量而言更加重要,从 PGC 切换至低延迟的 G1 能够为大部分用户带来更好的体验。G1 的性能在 JDK 8 以及后续的 release 版本都得到了极大的优化,G1 是一个具备所有 GC 特性的垃圾回收器,因此将 G1 设置为 JVM 默认的 GC。

根据 JEP-291 中的说明,为了减轻 GC 代码的维护负担以及加速新功能开发,决定在 JDK 9 中废弃 CMS GC。

从 Java 9 开始,如果您使用 -XX:+UseConcMarkSweepGC(激活 CMS GC 算法的参数)参数启动应用程序,则会在下面显示警告消息:

  JavaHotSpot(TM)64-BitServerVMwarning:OptionUseConcMarkSweepGCwasdeprecated inversion9.0andwilllikelyberemoved inafuturerelease.


如果你想知道当前应用对应的 JVM 版本,你可以使用以下命令进行查询:

          G1将整个 JVM堆划分成多个大小相等的独立区域 regin,跟踪各个 regin里面的垃圾堆积的价值大小,在后台维护一个优先列表,每次根据允许的收集时间,有线回收最大的 regin,芮然还保留有新生代和老年代的概念,但新生代和老年代不在是物理隔离了,他们都是一部分 regin集合。

内存“化整为零”的思路:在 GC根节点的枚举范围汇总加入remembered set 即可保证不对全堆扫面也不会遗漏。

  「回收步骤」:
  1. 初始标记:标记 GC Roots直接关联的对象
  2. 并发标记:对堆中对象进行可达性分析,找出存活对象,耗时长,与用户进程并发工作
  3. 最终标记:修正并发标记期间用户进程继续运行而产生变化的标记
  4. 筛选回收:对各个 regin的回收价值进行排序,然后根据期望的 GC停顿时间制定回收计划
  G1收集器优势

  「并行与并发」: G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-The-World停顿时间。部分收集器原本需要停顿Java线程来执行 GC动作, G1收集器仍然可以通过并发的方式让Java程序继续运行。

  「分代收集」: G1能够独自管理整个Java堆,并且采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次 GC的旧对象以获取更好的收集效果。

  「空间整合」: G1运作期间不会产生空间碎片,收集后能提供规整的可用内存。

  「可预测的停顿」: G1除了追求低停顿外,还能建立可预测的停顿时间模型。能让使用者明确指定在一个长度为M毫秒的时间段内,消耗在垃圾收集上的时间不得超过N毫秒。

          收集过程:

           G1的回收过程主要分为 3 类:

(1) G1“年轻代”的垃圾回收,同样叫 Minor G1,这个过程和我们前面描述的类似,发生时机就是 Eden 区满的时候。

(2)老年代的垃圾收集,严格上来说其实不算是收集,它是一个“并发标记”的过程,顺便清理了一点点对象。

(3)真正的清理,发生在“混合模式”,它不止清理年轻代,还会将老年代的一部分区域进行清理。

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

   ZGC

  ZGC(Z Garbage Collector)是一款由Oracle公司研发的,以低延迟为首要目标的一款垃圾收集器。它是基于 「动态Region」内存布局,(暂时) 「不设年龄分代」,使用了 「读屏障」、 「染色指针」和 「内存多重映射」等技术来实现 「可并发的标记-整理算法」的收集器。

在 JDK 11新加入,还在实验阶段,主要特点是: 「回收TB级内存(最大4T),停顿时间不超过 10ms」。

  「优点」:低停顿,高吞吐量, ZGC收集过程中额外耗费的内存小

  「缺点」:浮动垃圾

目前使用的非常少,真正普及还是需要写时间的。

  21.垃圾收集器之间有什么关系?

  「新生代收集器」:Serial、 ParNew、 Parallel Scavenge

  「老年代收集器」: CMS、Serial Old、Parallel Old

  「整堆收集器」: G1, ZGC(因为不涉年代不在图中)

  22.如何选择垃圾收集器?

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

选择建议:
  1.   如果你的堆大小不是很大(比如 100MB),选择串行收集器一般是效率最高的。

    参数: -XX:+UseSerialGC。
  2.   如果你的应用运行在单核的机器上,或者你的虚拟机核数只有 单核,选择串行收集器依然是合适的,这时候启用一些并行收集器没有任何收益。

    参数: -XX:+UseSerialGC。
  3.   如果你的应用是“吞吐量”优先的,并且对较长时间的停顿没有什么特别的要求。选择并行收集器是比较好的。

    参数: -XX:+UseParallelGC。
  4.   如果你的应用对响应时间要求较高,想要较少的停顿。甚至 1 秒的停顿都会引起大量的请求失败,那么选择 G1、 ZGC、 CMS都是合理的。虽然这些收集器的 GC 停顿通常都比较短,但它需要一些额外的资源去处理这些工作,通常吞吐量会低一些。

    参数: -XX:+UseConcMarkSweepGC、 -XX:+UseG1GC、 -XX:+UseZGC等。
从上面这些出发点来看,我们平常的 Web 服务器,都是对响应性要求非常高的。选择性其实就集中在 CMS、 G1、 ZGC上。而对于某些定时任务,使用并行收集器,是一个比较好的选择。

  23.熟悉哪些JVM调优参数?

X或者XX开头的都是非转标准化参数

          意思就是说准表化参数不会变,非标准化参数可能在每个 JDK版本中有所变化,但是就目前来看X开头的非标准化的参数改变的也是非常少。

  格式:-XX:[+-]<name>表示启用或者禁用name属性。
例子:-XX:+UseG1GC(表示启用G1垃圾收集器)

  堆设置

  -Xms初始堆大小,ms是memory start的简称 ,等价于 -XX:InitialHeapSize -Xmx最大堆大小,mx是memory max的简称 ,等价于参数 -XX:MaxHeapSize
   注意:在通常情况下,服务器项目在运行过程中,堆空间会不断的收缩与扩张,势必会造成不必要的系统压力。所以在生产环境中, JVM的 Xms和 Xmx要设置成一样的,能够避免 GC在调整堆大小带来的不必要的压力。
  -XX:NewSize=n设置年轻代大小 -XX:NewRatio=n设置年轻代和年老代的比值。如: -XX:NewRatio=3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4,默认新生代和老年代的比例=1:2。 -XX:SurvivorRatio=n年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个,默认是8,表示

  Eden:S0:S1=8:1:1

如: -XX:SurvivorRatio=3,表示 Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5。

  -XX:MaxPermSize=n设置持久代大小

  -XX:MetaspaceSize设置元空间大小

  收集器设置

  -XX:+UseSerialGC设置串行收集器 -XX:+UseParallelGC设置并行收集器 -XX:+UseParalledlOldGC设置并行年老代收集器 -XX:+UseConcMarkSweepGC设置并发收集器

  垃圾回收统计信息

  -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:filenameGC日志输出到文件里 filename,比如: -Xloggc:/gc.log

  并行收集器设置

  -XX:ParallelGCThreads=n设置并行收集器收集时使用的CPU数。并行收集线程数。

  -XX:MaxGCPauseMillis=n设置并行收集最大暂停时间

  -XX:GCTimeRatio=n设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

  -XX:MaxGCPauseMillis=n设置并行收集最大暂停时间

  并发收集器设置

  -XX:+CMSIncrementalMode设置为增量模式。适用于单CPU情况。 -XX:ParallelGCThreads=n设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

  其他

  -XX:+PrintCommandLineFlags查看当前 JVM设置过的相关参数    

   Dump异常快照

  -XX:+HeapDumpOnOutOfMemoryError

  -XX:HeapDumpPath

堆内存出现 OOM的概率是所有内存耗尽异常中最高的,出错时的堆内信息对解决问题非常有帮助,所以给 JVM设置这个参数( -XX:+HeapDumpOnOutOfMemoryError),让 JVM遇到 OOM异常时能输出堆内信息,并通过( -XX:+HeapDumpPath)参数设置堆内存溢出快照输出的文件地址,这对于特别是对相隔数月才出现的 OOM异常尤为重要。

  -Xms10M-Xmx10M-Xmn2M-XX:SurvivorRatio=8-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D:\study\log_hprof\gc.hprof


  -XX:OnOutOfMemoryError

表示发生 OOM后,运行 jconsole.exe程序。这里可以不用加“”,因为 jconsole.exe路径Program Files含有空格。利用这个参数,我们可以在系统 OOM后,自定义一个脚本,可以用来发送邮件告警信息,可以用来重启系统等等。

  -XX:OnOutOfMemoryError= "C:\ProgramFiles\Java\jdk1.8.0_151\bin\jconsole.exe"

  24. 8G内存的服务器该如何设置?

  java-Xmx3550m-Xms3550m-Xss128k-XX:NewRatio=4-XX:SurvivorRatio=4-XX:MaxPermSize=16m-XX:MaxTenuringThreshold=0


  -Xmx3500m设置 JVM最大可用内存为3550M。

  -Xms3500m设置 JVM促使内存为 3550m。此值可以设置与 -Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。 -Xmn2g设置年轻代大小为 2G。
   整个堆大小=年轻代大小 + 年老代大小 + 方法区大小
  -Xss128k设置每个线程的堆栈大小。 JDK1.5以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

  -XX:NewRatio=4设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 。

  -XX:SurvivorRatio=4设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6 -XX:MaxPermSize=16m设置持久代大小为16m。

  -XX:MaxTenuringThreshold=0设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

                      

----------------------------
原文链接:https://blog.51cto.com/10983206/2570530

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2021-01-12 10:25:38 重新编辑]
  Java面向对象编程-->按面向对象开发的基础范例
  JavaWeb开发-->JSP中使用JavaBean(Ⅱ)
  JSP与Hibernate开发-->映射对象标识符
  Java网络编程-->通过JavaMail API收发邮件
  精通Spring-->Vue组件开发高级技术
  Vue3开发-->虚拟DOM和render()函数
  利用堆栈将中缀表达式转换成后缀表达式
  NIO底层原理
  Java设计模式: 单一职责原则和依赖倒置原则详解
  内部类的种类和用法
  Java方法的嵌套与递归调用
  java万年历简单制作
  java中的Static、final、Static final各种用法
  java常见的几种调用机制:同步调用,异步调用,回调
  Synchronized与ReentrantLock区别总结
  Java设计模式:解释器模式
  java比c++强大之处JVM垃圾收集算法
  Java入门实用代码:链表元素查找
  判断一个字符是否是汉字
  jdbc连接各种数据库代码
  Java中的main()方法详解
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。