灵魂拷问

为什么需要?

对什么东西?

在什么时候?

做什么事情?

一、为什么需要

应用程序对资源操作,通常简单分为以下几个步骤:

为对应的资源分配内存

初始化内存

使用资源

清理资源

释放内存

手动管理的话,容易造成以下典型问题:

程序员忘记释放内存

应用程序访问已经释放的内存

从而导致了内存泄漏、数据内容乱码等

总结:无法自动化的内存管理方式极易产生bug,影响系统稳定性,源源不断的类似bug影响开发人员编程积极性

二、对什么东西

垃圾收集主要是针对堆和方法区里不使用的对象进行的。程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后就会消失,因此不需要对这三个区域进行垃圾回收。

JVM是一个内存中的虚拟机,目前有三大Java虚拟机:HotSpot,oracle JRockit,IBM J9

Class Loader:根据特定格式,加载Class文件到内存

Runtime Data Area:JVM内存空间结构模型(也叫运行时数据区域)

Execution Engine:对命令进行解析

Native Interface:融合不同开发语言的原生库为Java所用,在执行时加载Native Libraries

2.1 运行时数据区域(Runtime Data Area)

JDK 1.6 运行时数据区域

JVM内存模型-JDK1.8

线程私有

程序计数器(字节码指令 no OOM)

虚拟机栈(Java方法 SOF&OOM)

本地方法栈(native方法 SOF&OOM)

线程共享

MetaSpace(类加载信息 OOM)

Java堆(数组和类对象 OOM,常量池)

JDK1.7中把运行时常量池放到了堆中。

JDK1.8及之后,由于每次Full GC之后永久代大小都会改变,经常OOM,所以把方法区(一种JVM规范,永久代和元空间都是它的实现方式,之前HotSpot虚拟机把这个作为永久代来进行垃圾回收)去掉了,移至元空间,而其原本的数据也分成两部分,元空间存储类的元信息,静态变量和常量池等都放到了堆中。

Java堆

所有对象都在这里分配内存,是垃圾收集的主要区域(GC 堆)

现代的垃圾收集器基本都是采用分代收集算法,其主要的思想是针对不同类型的对象采取不同的垃圾回收算法。可以将堆分成两块:

新生代(Young Generation):一个Eden,两个Survivor区,HopSpot默认大小8:1:1

老年代(Old Generation)

HotSpot Heap Structure

永久代(HotSpot的方法区)在JDK1.8之后移除,Java堆里只有新生代和老年代了。

堆不需要连续内存,并且可以动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。

2.2 怎么判断一个对象是否可被回收

2.2.1 引用计数算法

为对象添加一个引用计数器

当对象增加一个引用时计数器加 1,引用失效时计数器减 1

引用计数为 0 的对象可被回收

优点:执行效率高,程序执行受影响较小

缺点:无法检测出循环引用的情况,导致内存泄漏,因此Java虚拟机不实用引用技术算法

2.2.2 可达性分析算法

以 GC Roots为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收

可以作为GC Roots的对象

虚拟机栈中引用的对象(栈帧中的局部变量表)

方法区中的常量引用的对象

方法区中的类静态属性引用的对象

本地方法栈中JNI(native方法)的引用对象

可被回收

未到达的对象并非是“非死不可”的,若要宣判一个对象死亡,至少需要经历两次标记阶段

st=>start: 第一次标记&第一次筛选

e=>end: 被回收

callFinallize=>condition: 是否有必要执行该对象的finallize方法

putFQueue=>operation: 放入F-Queue队列,虚拟机自动建立低优先级的Finalizer线程

selfSave=>condition: 是否在finalize中拯救了自己(只能拯救一次)

removeFromQueue=>operation: 从即将回收的集合中移除,等待下次回收

st->callFinallize

callFinallize(yes)->putFQueue->selfSave

selfSave(no)->e

selfSave(yes)->removeFromQueue

callFinallize(no)->e

如果对象可达性分析之后GC Roots搜索不到,会被第一次标记并进行一次筛选(是否有必要执行该对象的finallize方法)

未覆盖或者已执行的 --> 回收

已覆盖未执行的 --> 放入一个叫F-Queue的队列中,之后会有虚拟机自动建立的、低优先级的Finalizer线程去执行,而虚拟机不必要等待该线程执行结束,即虚拟机只负责建立线程,其他的让此线程区处理

对F-Queue中的对象进行第二次标记

如果对象在finalize方法中拯救了自己(只能拯救一次),即关联上了GC Roots引用链,则第二次标记的时候会将该对象从“即将回收”的集合中移除

如果对象还是没有拯救自己,则会被回收

package com.dyl.myspringboot;

/**

* @author dyl

* @date 2019/08/06

*/

public class FinalizeTest {

private static FinalizeTest finalize;

@Override

protected void finalize() throws Throwable {

super.finalize();

System.out.println("method finalize is running");

finalize = this;

}

public static void main(String[] args) throws Exception {

finalize = new FinalizeTest();

// 第一次执行,finalize方法会自救

finalize = null;

System.gc();

Thread.sleep(500);

if (finalize != null) {

System.out.println("I'm alive");

} else {

System.out.println("I'm dead");

}

// 第二次执行,finalize方法已经执行过

finalize = null;

System.gc();

Thread.sleep(500);

if (finalize != null) {

System.out.println("I'm alive");

} else {

System.out.println("I'm dead");

}

}

}

2.3 引用类型

无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象是否可达,判定对象是否可被回收都与引用有关

Java 提供了四种强度不同的引用类型

2.3.1 强引用

被强引用关联的对象不会被回收

使用 new一个新对象的方式来创建强引用

Object obj = new Object();

2.3.2 软引用

被软引用关联的对象只有在内存不够的情况下才会被回收

使用 SoftReference 类来创建软引用

Object obj = new Object();

SoftReference sf = new SoftReference(obj);

obj = null; // 使对象只被软引用关联

2.3.3. 弱引用

被弱引用关联的对象一定会被回收,也就是说它只能存活到下一次垃圾回收发生之前

使用 WeakReference 类来创建弱引用

Object obj = new Object();

WeakReference wf = new WeakReference(obj);

obj = null;

2.3.4 虚引用

又称为幽灵引用或者幻影引用,一个对象是否有虚引用的存在,不会对其生存时间造成影响,也无法通过虚引用得到一个对象

为一个对象设置虚引用的唯一目的是能在这个对象被回收时收到一个系统通知

使用PhantomReference 来创建虚引用

Object obj = new Object();

PhantomReference pf = new PhantomReference(obj, null);

obj = null;

强引用 > 软引用 > 弱引用 > 虚引用

引用类型

被垃圾回收时间

用途

生存时间

强引用

从来不会

对象的一般状态

JVM停止运行时终止

软引用

在内存不足时

对象缓存

内存不足时终止

弱引用

在垃圾回收时

对象缓存

GC运行后终止

虚引用

Unknown

标记、哨兵

Unknown

总结:引用计数为0的对象;从GC Roots开始搜索不到的对象,而且经过一次标记、清理,仍然没有复活的对象

三、在什么时候

3.1 内存分配策略

对象优先在 Eden 分配

大多数情况下,对象在新生代 Eden 上分配,当 Eden 空间不够时,发起 Minor GC

大对象直接进入老年代

大对象是指需要连续内存空间的对象,最典型的大对象是那种很长的字符串以及数组。 经常出现大对象会提前触发垃圾收集以获取足够的连续空间分配给大对象。

-XX:PretenureSizeThreshold大于此值的对象直接在老年代分配,避免在 Eden 和 Survivor 之间的大量内存复制

长期存活的对象进入老年代

为对象定义年龄计数器,对象在 Eden 出生并经过 Minor GC 依然存活,将移动到 Survivor 中,年龄就增加 1 岁, 增加到一定年龄则移动到老年代中。

-XX:MaxTenuringThreshold用来定义年龄的阈值

动态对象年龄判定

虚拟机并不是永远要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果在 Survivor 中相同年龄 所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代,无需等到 MaxTenuringThreshold 中要求的年龄。

3.2 内存回收策略

Minor GC

回收新生代,因为新生代对象存活时间很短,因此 Minor GC 会频繁执行,执行的速度一般也会比较快

Full GC

回收老年代和新生代,老年代对象其存活时间长,因此 Full GC 很少执行,执行速度会比 Minor GC慢很多

3.3 触发条件

3.3.1 Minor GC

当Eden空间满时,就将触发一次 Minor GC

3.3.2 Full GC

调用System.gc()

只是建议虚拟机执行 Full GC,但是虚拟机不一定真正去执行。不建议使用这种方式,而是让虚拟机管理内存

老年代空间不足

老年代空间不足的常见场景为 大对象直接进入老年代、长期存活的对象进入老年代等

为了避免,应当尽量不要创建过大的对象以及数组。除此之外,可以通过-Xmn虚拟机参数调大新生代的大小,让对象尽量在新生代被回收掉,不进入老年代。还可以通过-XX:MaxTenuringThreshold调大对象进入老年代的年龄,让对象在新生代多存活一段时间

JDK 1.7 及以前的永久代空间不足

在 JDK 1.7 及以前,HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些 Class 的信息、常量、静态变量等数据。

当系统中要加载的类、反射的类和调用的方法较多时,永久代可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么虚拟机会抛出 java.lang.OutOfMemoryError。

可采用增大永久代空间或转为使用 CMS GC的方法来避免

CMS GC时出现promotion failed,concurrent mode failure

预留的内存不够存放浮动垃圾

总结:新生代的Eden区空间满时触发Minor GC;系统在不可测的时间调用System.gc()方法、老年代空间不足、jdk1.7及以前的永久代空间不足等情况会触发Full GC

四、做什么事情

4.1 垃圾收集算法

4.1.1 标记-清除算法(Mark and Sweep)

标记:从根集合GC Roots进行扫描,对存活的对象进行标记

清除:对堆内存从头到尾进行线性遍历,回收不可达对象内存

缺点

标记和清除过程效率都不高

会产生大量不连续的内存碎片,导致无法给大对象分配内存

4.1.2 标记-整理算法(Compacting)

标记:从根集合进行扫描,对存活的对象进行标记

清除:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收

优点

避免内存的不连续行

不用设置两块内存互换

适用于存活率高的场景

缺点

需要移动大量对象,处理效率低

4.1.3 复制算法(Copying)

分为对象面和空闲面

对象在对象面上创建

存活的对象被从对象面复制到空闲面

将对象面所有对象内存清除

优点:

解决碎片化问题

顺序分配内存,简单高效

适用于对象存活率低的场景

4.1.4 分代收集算法(Generational Collector)

垃圾回收算法的组合拳

按照对象生命周期的不同划分区域以采取不同的垃圾回收算法

目的:提高JVM的回收效率

新生代:复制算法:HotSpot默认值 Eden : Survivor = 8 : 1

老年代:标记-清除 or 标记-整理

4.2 垃圾回收器

HotSpot的7个垃圾收集器

以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用

单线程与多线程

单线程指的是垃圾收集器只使用一个线程,而多线程使用多个线程

串行与并行

串行指的是垃圾收集器与用户程序交替执行,这意味着在执行垃圾收集的时候需要停顿用户程序;并行指的是垃圾收集器和用户程序同时执行。除了 CMS 和 G1 之外,其它垃圾收集器都是以串行的方式执行

4.2.1. Serial 收集器

它是单线程的收集器,只会使用一个线程进行垃圾收集工作。

它的优点是简单高效,在单个 CPU 环境下,由于没有线程交互的开销,因此拥有最高的单线程收集效率。

它是 Client 场景下的默认新生代收集器,因为在该场景下内存一般来说不会很大。它收集一两百兆垃圾的停顿时间可以控制在一百多毫秒以内,只要不是太频繁,这点停顿时间是可以接受的

4.2.2. ParNew 收集器

它是 Serial 收集器的多线程版本。

它是 Server 场景下默认的新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合使用

4.2.3 Parallel Scavenge 收集器

与 ParNew 一样是多线程收集器。

其它收集器目标是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是达到一个可控制的吞吐量,因此它被称为吞吐量优先收集器。这里的吞吐量指 CPU 用于运行用户程序的时间占总时间的比值。

缩短停顿时间是以牺牲吞吐量和新生代空间来换取的:新生代空间变小,垃圾回收变得频繁,导致吞吐量下降。

4.2.4 Serial Old 收集器

是 Serial 收集器的老年代版本,也是给 Client 场景下的虚拟机使用。如果用在 Server 场景下,它有两大用途

在 JDK 1.5 以及之前版本(Parallel Old 诞生以前)中与 Parallel Scavenge 收集器搭配使用

作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用

4.2.5 Parallel Old 收集器

是 Parallel Scavenge 收集器的老年代版本。

在注重吞吐量以及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge 加 Parallel Old 收集器

4.2.6 CMS 收集器

CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法

分为以下四个流程:

初始标记:仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿

并发标记:进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿

重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿

并发清除:不需要停顿

在整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,不需要进行停顿。

具有以下缺点:

吞吐量低:低停顿时间是以牺牲吞吐量为代价的,导致 CPU 利用率不够高

无法处理浮动垃圾,可能出现 Concurrent Mode Failure。浮动垃圾是指并发清除阶段由于用户线程继续运行而产生的垃圾,这部分垃圾只能到下一次 GC 时才能进行回收。由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure,这时虚拟机将临时启用 Serial Old 来替代 CMS

标记 - 清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前触发一次 Full GC

4.2.7 G1 收集器

G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,在多 CPU 和大内存的场景下有很好的性能。

HotSpot 开发团队赋予它的使命是未来可以替换掉 CMS 收集器

堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收

总结:触发GC时,JVM根据分代收集算法,使用相应的垃圾收集器来回收垃圾

个人观点

Java GC,打个不太形象的比喻,就好比拿扫把扫地:

哪些是垃圾(可达性分析,把有用的标记)

哪里的垃圾(Runtime Data Area是房间,Java堆是地板)

什么时候扫?(GC触发条件)

用什么扫?(垃圾回收器)

怎么扫?(垃圾收集算法)

JVM性能调优常用参数

参数名称

含义

默认值

说明

-Xms

初始堆大小

物理内存的1/64(<1GB)

默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制

-Xmx

最大堆大小

物理内存的1/4(<1GB)

默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制

-Xmn

新生代大小(1.4or lator)

注意:此处的大小是(eden+ 2 survivor space)。与jmap -heap中显示的New gen是不同的。整个堆大小=新生代大小+老年代大小+永久代大小。增大新生代后,将会减小老年代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8

-XX:NewSize

设置新生代大小(for 1.3/1.4)

-XX:MaxNewSize

新生代最大值(for 1.3/1.4)

-XX:PermSize

设置永久代(perm gen)初始值

物理内存的1/64

jdk1.8之后不生效

-XX:MaxPermSize

设置永久代最大值

物理内存的1/4

jdk1.8之后不生效

-Xss

每个线程的堆栈大小

JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。一般小的应用,如果栈不是很深,应该是128k够用的,大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试

-XX:ThreadStackSize

Thread Stack Size

(0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.]

-XX:NewRatio

新生代(包括Eden和两个Survivor区)与老年代的比值(除去永久代)

-XX:NewRatio=4表示新生代与老年代所占比值为1:4,新生代占整个堆栈的1/5Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。

-XX:SurvivorRatio

Eden区与Survivor区的大小比值

HotSpot默认设置为8,即两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个新生代的1/10

-XX:LargePageSizeInBytes

内存页的大小不可设置过大, 会影响Perm的大小

=128m

-XX:+UseFastAccessorMethods

原始类型的快速优化

-XX:+DisableExplicitGC

关闭System.gc()

这个参数需要严格的测试

-XX:MaxTenuringThreshold

垃圾最大年龄

如果设置为0的话,则新生代对象不经过Survivor区,直接进入老年代。对于老年代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则新生代对象会在Survivor区进行多次复制,这样可以增加对象再新生代的存活时间,增加在新生代即被回收的概率。该参数只有在串行GC时才有效

-XX:+AggressiveOpts

加快编译

-XX:+UseBiasedLocking

锁机制的性能改善

-Xnoclassgc

禁用垃圾回收

-XX:SoftRefLRUPolicyMSPerMB

每兆堆空闲空间中SoftReference的存活时间

1s

softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap

-XX:PretenureSizeThreshold

对象超过多大是直接在老年代分配

0

单位字节 新生代采用Parallel Scavenge GC时无效,另一种直接在老年代分配的情况是大的数组对象,且数组中无外部引用对象

-XX:TLABWasteTargetPercent

TLAB占eden区的百分比

1%

-XX:+CollectGen0First

FullGC时是否先YGC

false

JVM性能调优工具

先进入到jdk的目录

[dengyulong@09:20:14]~$ /usr/libexec/java_home -V

Matching Java Virtual Machines (1):

1.8.0_201, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home

[dengyulong@09:23:50]~$ cd /Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/bin

[dengyulong@09:27:16]/Library/Java/JavaVirtualMachines/jdk1.8.0_201.jdk/Contents/Home/bin$ ls

appletviewer java javap jdeps jmc jstat orbd rmiregistry unpack200

extcheck javac javapackager jhat jps jstatd pack200 schemagen wsgen

idlj javadoc jcmd jinfo jrunscript jvisualvm policytool serialver wsimport

jar javafxpackager jconsole jjs jsadebugd keytool rmic servertool xjc

jarsigner javah jdb jmap jstack native2ascii rmid tnameserv

1. jps

查看JVM中运行的进程状态信息

[dengyulong@09:33:03]~$ jps

16224 Bootstrap

30529

27157 Bootstrap

53030 Main

24376 Bootstrap

52637 Launcher

52845 Launcher

52846 Bootstrap

53150 Jps

2. jstack

查看某个Java进程内的线程堆栈信息

$ jstack [pid]

3. jstat

查看各个区内存和GC的情况

-class

显示加载class的数量,及所占空间等信息

[dengyulong@10:29:28]~$ jstat -class 30529

Loaded Bytes Unloaded Bytes Time

145689 253316.0 61218 80613.1 102.79

Loaded : 已经装载的类的数量

Bytes : 装载类所占用的字节数

Unloaded:已经卸载类的数量

Bytes:卸载类的字节数

Time:装载和卸载类所花费的时间

-compiler

显示VM实时编译(JIT)的数量等信息

[dengyulong@15:04:33]~$ jstat -compiler 30529

Compiled Failed Invalid Time FailedType FailedMethod

402707 25 0 5391.41 1 com/intellij/psi/impl/compiled/StubBuildingVisitor visitMethod

Compiled:编译任务执行数量

Failed:编译任务执行失败数量

Invalid :编译任务执行失效数量

Time :编译任务消耗时间

FailedType:最后一个编译失败任务的类型

FailedMethod:最后一个编译失败任务所在的类及方法

-gc

显示gc相关的堆信息,查看gc的次数,及时间

[dengyulong@15:04:40]~$ jstat -gc 30529

S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT

38336.0 38336.0 10431.9 0.0 306944.0 93751.1 769408.0 475510.8 567576.0 517967.3 72696.0 63593.5 9158 131.185 683 362.332 493.517

S0C:新生代中第一个 survivor 的容量(Byte)

S1C:新生代中第二个 survivor 的容量(Byte)

S0U:新生代中第一个 survivor 目前已使用空间(Byte)

S1U:新生代中第二个 survivor 目前已使用空间(Byte)

EC:新生代中 Eden 的容量(Byte)

EU:新生代中 Eden 目前已使用空间(Byte)

OC:老年代的容量(Byte)

OU:老年代目前已使用空间(Byte)

MC:metaspace(元空间)的容量(Byte)

MU:metaspace(元空间)目前已使用空间(Byte)

YGC:从应用程序启动到采样时新生代中gc次数

YGCT:从应用程序启动到采样时新生代gc(Minor GC)所用时间(s)

FGC:从应用程序启动到采样时老年代gc(Full GC)次数

FGCT:从应用程序启动到采样时老年代gc(Full GC)所用时间(s)

GCT:从应用程序启动到采样时gc用的总时间(s)

-gcutil

统计gc信息

[dengyulong@15:17:22]~$ jstat -gcutil 30529

S0 S1 E O M CCS YGC YGCT FGC FGCT GCT

0.00 0.00 53.89 63.02 91.26 87.48 9159 131.207 684 363.946 495.153

S0:新生代中第一个survivor已使用的占当前容量百分比

S1:新生代中第二个survivor已使用的占当前容量百分比

E:新生代中Eden已使用的占当前容量百分比

O:老年代已使用的占当前容量百分比

M:Metaspace已使用的占当前容量百分比

YGC:从应用程序启动到采样时新生代中gc次数

YGCT:从应用程序启动到采样时新生代中gc所用时间(s)

FGC:从应用程序启动到采样时老年代GC(Full GC)次数

FGCT:从应用程序启动到采样时老年代GC(Full GC)所用时间(s)

GCT:从应用程序启动到采样时gc用的总时间(s)

其他的如:-gccapacity、-gcmetacapacity、-gcnew、-gcnewcapacity、-gcold、-gcoldcapacity、-gccause、-printcompilation按需使用,这里不多做介绍

4. jvisualvm

JDK自带监控程序

jvisualvm的监控界面

java gc什么意思_对Java GC的简单理解相关推荐

  1. java项目----教务管理系统_基于Java的教务管理系统

    java项目----教务管理系统_基于Java的教务管理系统 2022-04-22 18:18·java基础 最近为客户开发了一套学校用教务管理系统,主要实现学生.课程.老师.选课等相关的信息化管理功 ...

  2. java超出gc开销限制_超出了GC开销限制– Java堆分析

    java超出gc开销限制 这篇文章是我们原来的GC开销超出问题模式的延续. 正确的Java堆分析对于消除O​​utOfMemoryError:GC开销问题至关重要. 如果您不熟悉此Java HotSp ...

  3. java pdf插件下载_免费java pdf控件

    云原生的概念和理论体系非常的完备,but talk is cheap , show me the code ! 但是作为一名程序员,能动手的咱绝对不多BB,虽然talk并不cheap , 能跟不同层次 ...

  4. java垃圾回收机制_笔记 | Java垃圾回收机制

    本文经授权转载自程序员杂货铺(ID:speakFramework) 垃圾回收 最近上海的小伙伴是不是要被强垃圾分类搞疯了???哈哈哈哈 上海是个走在前列的城市啊,不光骑自行车闯红灯要被罚钱,垃圾不分类 ...

  5. java表底层生产工具_使用Java工具解决生产故障(一)-jcmd介绍

    1.简介 Java开发的应用程序在线上出现生产故障很常见,通常我们会在开发环境模拟此类故障,但偶尔也会遇到无法成功模拟的故障.那么我们就需要在生产环境上进行分析,定位故障产生原因.JDK1.7版本之后 ...

  6. java代码耗尽内存_有关Java内存溢出及内存消耗的小知识

    内存溢出原理: 我们知道,Java程序本身是不能直接在计算机上运行的,它需要依赖于硬件基础之上的操作系统和JVM(Java虚拟机). Java程序启动时JVM都会分配一个初始内存和最大内存给这个应用程 ...

  7. java runnable线程锁_多线程 java 同步 、锁 、 synchronized 、 Thread 、 Runnable

    线程 1 线程概述 1.1 什么是线程 v  线程是程序执行的一条路径, 一个进程中可以包含多条线程 v  一个应用程序可以理解成就是一个进程 v  多线程并发执行可以提高程序的效率, 可以同时完成多 ...

  8. JAVA解决实例问题_解决java方法

    没有R.java问题找不到getActionBar()方法 android项目,可是项目中没有重要的R.java,并且报错,说是找不到getActionBar()方法,上网寻找原因,终于寻得解决方法: ...

  9. 6种java垃圾回收算法_学习java垃圾回收

    垃圾回收(GC)一直是Java受欢迎背后的重要特性之一.垃圾回收是Java中用于释放未使用的内存的机制.本质上,它追踪所有仍在使用的对象,并将剩下的标记为垃圾.Java的垃圾回收被认为是一种自动内存管 ...

  10. java 查看堆内存_查看java内存情况的几个常用命令

    1.jinfo jinfo:的用处比较简单,就是能输出并修改运行时的java进程的运行参数.用法是jinfo -opt pid 如:查看52606的MaxPerm大小可以用 jinfo -flag M ...

最新文章

  1. golang模板语法
  2. ABB 机器人 DRVIO_1通信报警
  3. 硬币问题——固定终点的最长路和最短路
  4. 我对CSS vertical-align的一些理解与认识(二)
  5. JAVA—HTTP客户端警告:Going to buffer response body of large or unknown size.
  6. java 时间戳转换成时间_java 10位时间戳 转成时间
  7. tcp测试监听工具_linux 下两款网络性能测试工具介绍
  8. (四)洞悉linux下的Netfilteramp;iptables:包过滤子系统iptable_filter
  9. Nginx源码分析 - HTTP模块篇 - HTTP Request解析过程(22)
  10. docker给php装swoole,制作php+swoole的Docker环境
  11. 【收藏】Windows 8 Consumer Preview的108个运行命令及简要说明
  12. matlab人口增长模型拟合,matlab曲线拟合人口增长模型及其数量预测
  13. hibernate mappedBy属性详解!
  14. 读书笔记-人月神话8
  15. synchronized加锁过程
  16. UG8.5中nxopen.dll等文件所在位置
  17. PDF.js 在线pdf阅读插件(禁止打印,下载,每页水印)
  18. 服装管理系统总体概述
  19. Arduino控制RGB灯(WS2812B)
  20. 继承 java_继承

热门文章

  1. idea java 远程调试_如何使用 Idea 远程调试 Java 代码
  2. 【JAVA】Socket文件上传遇到的问题!~
  3. 企业微信绑定企业邮箱服务器配置,企业微信企业邮箱开通规则说明介绍
  4. 【图像压缩】基于PCNN实现图像的压缩重建附matlab代码
  5. WordPress 最新RiPro9.0修正升级版+WP两款美化包+稀有插件
  6. Matlab 几种画图方式总结
  7. JS基础-DOM增删改-尚硅谷视频p103
  8. java求1~20阶乘之和
  9. 激光雷达科普(1):激光雷达的分类及重要参数
  10. python解析word拆分Excel选择题格式(3、判断题)