1. JVM的自动内存管理机制

1.1 运行时数据区域

jvm 1.7

1.1.1 程序计数器(PC Register)

  • 当前线程所执行字节码的行号指示器,字节码解释器的作用是通过改变计数器的值来选取下一条需要执行的字节码指令。
  • 如果当前执行的是Native方法,则这个计数器为空。
  • Java虚拟机中唯一没有OOM的区域。

1.1.2 Java虚拟机栈 (JVM Stack)

  • 虚拟机栈描述的是Java方法执行的内存模型,生命周期与线程相同。
  • 每个方法运行都会创建一个栈帧,存储局部变量表(Local Variable Table),操作栈(Operation Stack),方法出口等信息。
  • 在编译期分配局部变量表存放各种基本数据类型、对象引用类型和returnAddress(指向一条字节码指令的地址)。
  • 如果请求的栈深度大于最大可用栈深度时,系统就会抛出StackOverflowError错误。
  • 如果虚拟机动态扩展无法申请到足够的的内存时会抛出OOM异常。大部分虚拟机都可以动态扩展,当然也允许固定长度虚拟机栈。

1.1.3 本地方法栈(Native Method Stack)

  • 虚拟机栈为执行Java方法服务,本地方法栈为Native方法服务。
  • 会出现OOM或者StackOverflowError,原因和虚拟机栈类似。

1.1.4 Java堆(Heap)

  • 虚拟机启动时创建被所有线程共享的内存区域,为了存储所有对象实例和数组。垃圾回收的主要区域。

1.1.5 方法区(Method Area)

  • 别名:“永久代“、”非堆,各个线程共享的内存区域,存储虚拟机已加载的类信息,静态变量、常量、即时编译器编译后的代码数据。默认最小为16MB,最大为64MB,可以通过-XX:PermSize和-XX:MaxPermSize 参数限制方法区大小。
  • Java8中,已经彻底没有了永久代,将方法区直接放在一个与堆不相连的本地内存区域,这个区域被叫做元空间。

1.1.6 运行时常量池(Runtime Constant Pool)

  • 运行时常量池:jdk1.6及之前是方法区的一部分,其中的主要内容来自于JVM对Class的加载。Java7中已经将运行时常量池从方法区(永久代)移除,在Java 堆(Heap)中开辟了一块区域存放运行时常量池。
  • 类加载后存储编译器生成的常量(各种字面量和符号引用)。基本数据类型不叫常量,可被修改,String和final修饰的才是。字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念,包括了如下三种类型的常量:类和接口的全限定名、字段名称和描述符、方法名称和描述符。
  • 由于运行时常量池从方法区移动到堆,所以jdk1.6和jdk1.7对于常量池的使用还是有些区别的,深入解析String#intern

1.1.7 直接内存(Direct Memory)

  • 堆外内存,JVM虚拟机各个区域内存总和大于机器物理内存可能会导致OOM。

1.2 对象状态算法

  • 引用计数算法: 很难解决对象之间相互引用的问题,内存泄露。

  • 跟搜索算法:通过一系列名为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索的路径成为引用链,当一个对象到GC Root没有一个引用时,则证明此对象是不可用的。

注:1. GC对象包括:虚拟机栈(栈帧中的本地变量表)中引用的对象,方法区中类静态属性引用的对象,方法区中常量引用的对象,本地方法栈中JNI。2. 跟搜索算法中,没有引用的对象并非非死不可,还有经历两次标记,第一次发现没有引用,则进行标记,并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方法或finalize()已经被调用过,虚拟机将这两种情况都视为没有必要执行。

1.2.1 回收方法区

方法区主要回收废弃变量和无用的类。无用的类:该类所有实例都已被回收,加载该类的ClassLoader被回收,该类对应的java.lang.Class对象没有在任何地方被引用。只有同时满足无用的类的三个条件,才可以被回收。反射、动态代理、CGLib等bytecode框架场景以及频繁定义ClassLoader的场景都需要具备卸载功能,以保证永久代不会溢出。

1.3 垃圾收集算法

  • 标记清除算法: 标记所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。效率问题,空间问题(内存碎片)。

  • 复制算法: 新生代使用复制算法回收,由于新生代98%的对象都是朝生夕死的,所以不需要1:1的比例划分内存空间(Hotspot默认8:1),而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一个Survivor。当回收时,将Eden和Survivor中还存活的对象一次性的拷贝到另一块的Survivor上。最后清理掉Eden和刚才使用过的Survivor。当Survivor空间不够用时,需要依赖其他的老年代进行分配担保(Handle Promotion)。分配担保:如果Survivor空间没有足够的空间存放上次新生代收集下来的存活对象,这些对象将直接通过分配担保机制进入老年代。

  • 标记-整理算法:让所有存活的对象向一端移动,然后清理掉端边界以外的内存。老年代常用的算法。

  • 分代收集算法: 根据对象的存活周期不同,将内存划分为几块,根据各个年代的特点进行垃圾回收。

1.4 垃圾收集器

垃圾回收器
图片来自《深入理解Java虚拟机》
如果两个收集器之间存在连线,就说明他们可以搭配使用。

  1. Serial

    复制算法,新生代的单线程收集器,简单高效,stop the world。

  2. ParNew

    复制算法,Serial的多线程版本,stop the world。首选的新生代收集器。

  3. Parallel Scavenge

    新生代收集器,使用复制算法,多线程并行, stop the world。目标达到可控制的吞吐量。运行用户代码时间/CPU消耗总时常=吞吐量。该收集器提供两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMills参数及直接设置吞吐量大小的-XX:GCTimeRatio参数。MaxGCPauseMills参数允许的值是一个大于0的毫秒数,收集器将尽力保证内存回收花费的时间不超过设定值。GCTimeRatio参数的值应该是一个大于0的整数,也就是垃圾收集时间占总时间的比率,相当于吞吐量的倒数。除了这两个参数,还有一个-XX:+UseAdaptiveSizePolicy值得关注。打开这个参数后,不需要手工指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大吞吐量这种方式称为GC自适应的调节策略(GC Ergonomics)

  4. Serial Old

    Serial收集器的老年代版本,单线程收集器,使用标记-整理算法,stop the world。主要有两个用途:1. 在JDK1.5及之前的版本中与Parallel Scavenge收集器搭配使用,另外一个就是作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure的时候用。

  5. Parallel Old

    Parallel Scavenge的老年代版本,标记-整理算法,stop the world。

  6. CMS(Concurrent Mark Sweep)收集器

最短回收停顿时间为目标的收集器,重视服务响应速度,标记-清除算法实现。第一款并发收集器,可与用户线程并发执行。执行过程分为4个步骤:初始标记(CMS initial mark)、并发标记(CMS concurrent mark)、重新标记(CMS remark)、并发清除(CMS concurrent sweep)。初始和重新stop the world。初始标记只是标记GCRoots能直接关联的对象,速度很快,并发标记进行GCROOTs Tracing的过程。重新标记为了修复并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。
优点:并发收集、低停顿。
缺点:1. 对CPU资源非常敏感,解决方案,减少GC线程的独占时间。2. 无法处理浮动垃圾。CMS运行期间,用户线程产生的垃圾为浮动垃圾,CMS无法在本次收集中个清理这些浮动垃圾。如果CMS运行期间,内存无法满足用户线程要求,就会出现Concurrent Mode Failure失败,可能导致另一个FullGC产生,启动预备方案 Serial Old。3. 产生大量的空间碎片。

  1. G1收集器

    标记整理算法实现,精确的控制停顿,指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不超过N毫秒。G1将整个Java堆(老年代,新生代)划分多个大小固定的独立区域(Region),并且追踪这些区域里面的垃圾堆积程度。在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域。

1.5 内存分配与回收

对象在Eden中分配内存,没有足够的空间进行垃圾回收。MinorGC。

MinorGC: 新生代垃圾回收的动作,频繁且速度快。

MajorGC(FullGC): 指发生在老年代的GC,慢,清理新生代和老年代,CMS

大对象指需要大量连续空间的Java对象。典型就是很长的字符串和数组。直接进入老年代分配,避免在Eden及Survivor中大量复制拷贝。

长期生活的对象进入老年代。对象年龄计数器,每一次MinorGC增长1岁。默认15岁进入老年代。

动态对象年龄判断,如果在Survivor空间中,相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄段的对象直接进入老年代。

空间担保分配,每次MinorGC,检测升级到老年代的大小是否大于老年代的空间,如果大于,则进行FullGC。

2. JDK命令行工具 性能监控和故障处理

2.1 jps

虚拟机进程状况工具。 显示当前所有java进程pid的命令。

-l 输出主类的全名,如果进程执行的是Jar包,输出Jar路径

1
2
3
4
5
6
7

C:\Program Files\Java\jdk1.8.0_161\bin>jps -l
5696 com.intellij.rt.execution.application.AppMain
944 org.jetbrains.idea.maven.server.RemoteMavenServer
4488
1900 org.jetbrains.jps.cmdline.Launcher
7244 sun.tools.jps.Jps

-v 输出虚拟机进程启动时JVM参数

1
2
3
4
5
6
7
8
9
10
C:\Program Files\Java\jdk1.8.0_161\bin>jps -v
5696 AppMain -Didea.launcher.port=7534 -Didea.launcher.bin.path=F:\Program Files\intellij IDEA\bin -Dfile.encoding=UTF-8
944 RemoteMavenServer -Djava.awt.headless=true -Didea.version==2016.2.5 -Xmx768m -Didea.maven.embedder.version=3.0.5 -Dfile.encoding=GBK
1656 Jps -Denv.class.path=.;C:\Program Files\Java\jdk1.8.0_161\lib\dt.jar;C:\Program Files\Java\jdk1.8.0_161\lib\tools.jar; -Dapplication.home=C:\Program Files\Java\jdk1.8.0_161 -Xms8m
4488 -Xms128m -Xmx750m -XX:ReservedCodeCacheSize=240m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Djb.vmOptionsFile=F:\Program Files\intellij IDEA\bin\idea64.exe.v
moptions -Xbootclasspath/a:F:\Program Files\intellij IDEA\lib\boot.jar -Didea.paths.selector=IntelliJIdea2016.2 -Didea.jre.check=true -XX:ErrorFile=C:\Users\zhongyp\java_error_in_idea_%p.log -XX:HeapDumpPath=C:\Users\zhongyp\java_error_in_idea.hprof
1900 Launcher -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Djdt.compiler.useSingleThread=true -Dpreload.project.path=E:/demo -Dpreload.config.path=C:/Users/zhongyp/.IntelliJIdea2016.2/config/options -Dcompile.parallel=false -Drebuild.on.dependency.change=true -Djava.net.preferIPv4Stack=true
-Dio.netty.initialSeedUniquifier=-1505227146882843300 -Dfile.encoding=GBK -Djps.file.types.component.name=FileTypeManager -Duser.language=zh -Duser.country=CN -Didea.paths.selector=IntelliJIdea2016.2 -Didea.home.path=F:\Program Files\intellij IDEA -Didea.config.path=C:\Users\zhongyp\.IntelliJIdea2016.2\
config -Didea.plugins.path=C:\Users\zhongyp\.IntelliJIdea2016.2\config\plugins -Djps.log.dir=C:/Users/zhongyp/.IntelliJIdea2016.2/system/log/build-log -Djps.fallback.jdk.home=C:/Program Files/Java/jdk1.8.0_161/jre -Djps.fallback.jdk.version=1.8.0_161 -Djava.io.tmpdir=C:/Users/zhongyp/.IntelliJIdea2016.2/
system/compile-server/_temp_ -Dkotlin.incremental.compilation.experimental=true -Dkotlin.daemon.enabled -Dkotlin.daemon.cli

-q 只输出LVMID,省略主类的名称

1
2
3
4
5
6
C:\Program Files\Java\jdk1.8.0_161\bin>jps -q
5696
8912
944
4488
1900

-m 输出虚拟机进程启动时传递给主类main()函数的参数

1
2
3
4
5
6
7
8
9
C:\Program Files\Java\jdk1.8.0_161\bin>jps -m
5696 AppMain com.zhongyp.Test
944 RemoteMavenServer
10484 Jps -m
4488
1900 Launcher F:/Program Files/intellij IDEA/lib/log4j.jar;F:/Program Files/intellij IDEA/lib/jps-builders.jar;F:/Program Files/intellij IDEA/lib/netty-all-4.1.1.Final.jar;F:/Program Files/intellij IDEA/lib/annotations.jar;F:/Program Files/intellij IDEA/lib/rt/jps-plugin-system.jar;F:/Program Files/intel
lij IDEA/lib/jgoodies-forms.jar;F:/Program Files/intellij IDEA/lib/util.jar;F:/Program Files/intellij IDEA/lib/trove4j.jar;F:/Program Files/intellij IDEA/lib/jna.jar;F:/Program Files/intellij IDEA/lib/resources_en.jar;F:/Program Files/intellij IDEA/lib/oromatcher.jar;F:/Program Files/intellij IDEA/lib/id
ea_rt.jar;F:/Program Files/intellij IDEA/lib/openapi.jar;F:/Program Files/intellij IDEA/lib/javac2.jar;F:/Program Files/intellij IDEA/lib/snappy-in-java-0.5.1.jar;F:/Program Files/intellij IDEA/lib/jna-platform.jar;F:/Program Files/intellij IDEA/lib/forms_rt.jar;F:/Program Files/intellij IDEA/lib/jdom.ja
r;F:/Program Files/intellij IDEA/lib/asm-all.jar;F:/Program Files/intellij IDEA/lib/jps-

2.2 jstat

虚拟机统计信息监视工具,用于监视虚拟机各种运行状态信息的命令。可以显示本地或远程虚拟机进程中的类加载、内存、垃圾回收、JIT编译等运行数据。运行期定位虚拟机性能问题的首选工具。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

-class:监视类装载、卸载数量、总空间以及类装载所耗时间。

-gc:监视JAVA堆状况,包括Eden区、两个Survivor区、老年代、永久代等的容量、已用空间,GC已用时间合计等信息;

-gccapacity:监视内容与-gc基本相同,但输出主要关注 java堆各个区域使用到的最大、最小空间;

-gcutil:监视内容与-gc基本相同,便输出主要关注已使用空间占总空间的百分比;

-gccause:与-gcutil功能一样,但是会额外输出导致 一次GC产生的原因;

-gcnew:监视新生代GC状态;

-gcnewcapacity:监视内容与-gcnew基本相同,输出最要关注使用到的最大、最小空间;

-gcold:监视老年代GC状况;

-gcoldcapacity:监视内容与-gcold基本相同,输出主要关注使用到的最大、最小空间;

-gcpermcapacity:监视永久代使用到的最大、最小空间;

-compiler:输入JIT编译器编译过的方法,耗时等信息;

-printcompilation:输出已经被JIT编译的方法;

2.3 jinfo

1
2
3
4
5
6
7

-flag <name> :可查看虚拟机启动时显式指定的参数列表。
-flag [+|-]<name>:设置或取消VM参数
-flag <name>=<value>:给VM参数设置新值
-flags:可查看所有VM参数;
-sysprops:查看java系统参数;
<no option>:表示在不给定任何选项时,打印出以上所有的VM参数

实时的查看和调整虚拟机的各项参数。

2.4 jmap

1
2
3
4
5
6
7
8
9
10
11
12

-dump:生成java堆转储快照,格式为:-dump[live, ] format=b, file=<filename>,其中live子参数说明是否只dump出存活对象;

-finalizerinfo:显示在F-QueuiK 等待Finalizer线程执行finalize方法的对象。只在Linux/Solaris平台下有效;

-heap:显示java堆详细信息,如使用哪种回收器、参数配置、分代状况等。只在Linux/Solaris平台下有效;

-histo:显示堆中对象统计信息,包括类、实例数量、合计容量;

-permstat:以ClassLoader为统计口径显示永久代内存状态,只在Linux/Solaris平台有效;

-F:当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照,只在Linux/Solaris平台有效

Java内存映像工具。用于生成堆转储快照,还可以查询finalize()执行队列,Java堆和永久代的详细信息,如空间使用率、当前使用的哪种收集器等。

1
2
3
C:\Program Files\Java\jdk1.8.0_161\bin>jmap -dump:format=b,file=D:\test.bin 2768
Dumping heap to D:\test.bin ...
Heap dump file created

2.5 jhat

jhat D:\test.bin

分析jmap生成的堆转储快照,在浏览器查看。

2.6 jstack

用于生成虚拟机当前时刻的线程快照。线程快照就是当前虚拟机内每一条正在执行的方法堆栈的集合,生成快照的目的是定位线程出现长时间停顿的原因。

-F 当正常输出的请求不被响应时,强制输出线程堆栈

-l 除堆栈外,显示关于锁的附加信息

-m 如果调用到本地方法的话,可以显示c/c++的堆栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

public class Test {

public static void main(String[] args){

// Thread t1 = new Worker(1);
//
//
// t1.start();
final A a = new A();
final B b = new B();

new Thread(){
@Override
public void run(){
try {
sleep(3000);
} catch (InterruptedException e) {

}
a.getBLock(b);
}
}.start();

new Thread(){
@Override
public void run(){
try {
sleep(3000);
} catch (InterruptedException e) {

}
b.getALock(a);
}
}.start();

}

}


class A {

public synchronized void getBLock(B b){

b.getALock(this);
}

}

class B{

public synchronized void getALock(A a){
a.getBLock(this);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

C:\Program Files\Java\jdk1.8.0_161\bin>jps -m
1904 AppMain com.zhongyp.Test
944 RemoteMavenServer
11540 Jps -m
13204 Launcher F:/Program Files/intellij IDEA/lib/log4j.jar;F:/Program Files/intellij IDEA/lib/jps-builders.jar;F:/Program Files/intellij IDEA/lib/netty-all-4.1.1.Final.jar;F:/Program Files/intellij IDEA/lib/annotations.jar;F:/Program Files/intellij IDEA/lib/rt/jps-plugin-system.jar;F:/Program Files/inte
llij IDEA/lib/jgoodies-forms.jar;F:/Program Files/intellij IDEA/lib/util.jar;F:/Program Files/intellij IDEA/lib/trove4j.jar;F:/Program Files/intellij IDEA/lib/jna.jar;F:/Program Files/intellij IDEA/lib/resources_en.jar;F:/Program Files/intellij IDEA/lib/oromatcher.jar;F:/Program Files/intellij IDEA/lib/i
dea_rt.jar;F:/Program Files/intellij IDEA/lib/openapi.jar;F:/Program Files/intellij IDEA/lib/javac2.jar;F:/Program Files/intellij IDEA/lib/snappy-in-java-0.5.1.jar;F:/Program Files/intellij IDEA/lib/jna-platform.jar;F:/Program Files/intellij IDEA/lib/forms_rt.jar;F:/Program Files/intellij IDEA/lib/jdom.j
ar;F:/Program Files/intellij IDEA/lib/asm-all.jar;F:/Program Files/intellij IDEA/lib/jps-
4488



C:\Program Files\Java\jdk1.8.0_161\bin>jstack -F 1904
Attaching to process ID 1904, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.161-b12
Deadlock Detection:

Found one Java-level deadlock:
=============================

"Thread-0":
waiting to lock [email protected] ([email protected], a com/zhongyp/B),
which is held by "Thread-1"
"Thread-1":
waiting to lock [email protected] ([email protected], a com/zhongyp/A),
which is held by "Thread-0"

Found a total of 1 deadlock.

Thread 1: (state = BLOCKED)


Thread 18: (state = BLOCKED)
- com.zhongyp.A.getBLock(com.zhongyp.B) @bci=0, line=51 (Interpreted frame)
- com.zhongyp.B.getALock(com.zhongyp.A) @bci=2, line=59 (Interpreted frame)
- com.zhongyp.Test$2.run() @bci=18, line=38 (Interpreted frame)


Thread 17: (state = BLOCKED)
- com.zhongyp.B.getALock(com.zhongyp.A) @bci=0, line=59 (Interpreted frame)
- com.zhongyp.A.getBLock(com.zhongyp.B) @bci=2, line=51 (Interpreted frame)
- com.zhongyp.Test$1.run() @bci=18, line=26 (Interpreted frame)


Thread 16: (state = IN_NATIVE)
- java.net.DualStackPlainSocketImpl.accept0(int, java.net.InetSocketAddress[]) @bci=0 (Interpreted frame)
- java.net.DualStackPlainSocketImpl.socketAccept(java.net.SocketImpl) @bci=37, line=131 (Interpreted frame)
- java.net.AbstractPlainSocketImpl.accept(java.net.SocketImpl) @bci=7, line=409 (Interpreted frame)
- java.net.PlainSocketImpl.accept(java.net.SocketImpl) @bci=42, line=199 (Interpreted frame)
- java.net.ServerSocket.implAccept(java.net.Socket) @bci=60, line=545 (Interpreted frame)
- java.net.ServerSocket.accept() @bci=48, line=513 (Interpreted frame)
- com.intellij.rt.execution.application.AppMain$1.run() @bci=13, line=79 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=748 (Interpreted frame)


Thread 10: (state = BLOCKED)


Thread 9: (state = BLOCKED)


Thread 8: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove(long) @bci=59, line=143 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove() @bci=2, line=164 (Interpreted frame)
- java.lang.ref.Finalizer$FinalizerThread.run() @bci=36, line=209 (Interpreted frame)


Thread 7: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait() @bci=2, line=502 (Interpreted frame)
- java.lang.ref.Reference.tryHandlePending(boolean) @bci=54, line=191 (Interpreted frame)
- java.lang.ref.Reference$ReferenceHandler.run() @bci=1, line=153 (Interpreted frame)

3. JDK可视化工具

JConsole: Java监视与管理控制台。基于JMX的可视化监视和管理工具。监视Java堆和永久代的的变化趋势。

VisualVM: 多合一故障处理工具。

4. JVM调优案例

4.1 高性能硬件上的程序部署策略

使用64位JDK大内存。

问题:1.内存回收导致长时间停顿。2.64位JDK的性能测试结果普遍低于32位JDK。3.需要保证程序足够稳定,这种应用如果产生堆溢出几乎就无法产生堆转储快照。4. 相同程序64位JDK中消耗内存一般比32位大,这是由于指针膨胀和数据类型对其补白导致的。

使用若干个32位虚拟机建立逻辑集群来利用集群资源。

问题:1.尽量避免节点竞争全局资源,如并发写操作导致IO异常。2.很难高效率的利用某些资源池,比如连接池,导致一些节点满了,其他的还为零。3.各个节点仍然不可避免的受到32位的限制(2GB)。4.大量使用本地缓存的应用,改为集中式的缓存。

4.2 集群间同步导致内存溢出

4.3 堆外内存导致的溢出错误

4.4 外部命令导致系统缓慢

5. java内存模型和线程

5.1 java内存模型

5.1.1 主内存和工作内存

Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。

注: 这里说的变量包括了实例变量、静态字段和构成数组对象的元素,但不包括局部变量与方法参数,因为后者是线程私有,不会被共享,自然就不存在竞争问题。

引用