Java虚拟机内存

StackOverflowError

前段时间一个同事给了个错误。看完整个log信息,感觉很懵。相信很多人更熟悉的是另一个错误,即OutOfMemoryError。

Caused by: java.lang.StackOverflowError
	at java.net.SocketOutputStream.socketWrite0(Native Method)
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
	at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
	at oracle.net.ns.DataPacket.send(DataPacket.java:209)
	at oracle.net.ns.NetOutputStream.write(NetOutputStream.java:180)
	at oracle.jdbc.driver.T4CSocketOutputStreamWrapper.flush(T4CSocketOutputStreamWrapper.java:98)
	at oracle.jdbc.driver.T4CSocketOutputStreamWrapper.flush(T4CSocketOutputStreamWrapper.java:91)

OutOfMemoryError

简单来说就是年内存溢出。在操作系统层时,当分配内存时,若不够也会类似错误。不过在这里分两类:
1. JVM中为对象分配内存时,JVM内存区域溢出。
2. JVM中各个区域扩展空间时,系统内存不足。

对于第一种,如java.lang.OutOfMemoryError java heap space 就是堆空间不足。OutOfMemoryError PremGen space时,说明是方法区溢出。

JVM内存模型

相信很多人对这个图很眼熟。


注意:
灰色区域:线程共享

白色区域:各线程私有

程序计数器

是一块很小的内存空间。用于指示当前线程所执行的字节码的行号(执行Native方法时,为空)。比如控制分支、循环、跳转、异常处理、线程恢复等。之所以说“线程私有”,是因为每个线程都需要一个独立的程序计数器来保证切换线程后能恢复到正确的位置。

堆是JVM里面内存最大的一块区域。几乎所有的对象实例都在这里分配内存。当无法分配内存给实例时,抛出OutOfMemoryError。当然堆的大小也可以扩展,如果扩展不了也会抛出OutOfMemoryError。

方法区

从名字就知道,方法区用于存放已被虚拟机加载的类信息、常量、静态变量等。也就是我们俗称的“永久代”。当然这只是相对的,比如也会存在类卸载等。另外,方法区无法满足内存分配需求时,也会抛出OutOfMemoryError。
值得说的是,JVM中说的运行时常量池,比如字符串池等也是这个区域的一部分。

虚拟机栈

虚拟机栈用于执行Java方法,因此很容易知道它是线程私有的。JVM文档里:每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。因此每个方法执行时,都会有进栈和出栈。

平时,我们遇到的StackOverflowError异常,一般都是发生在这个区域。表示线程请求的栈深度大于虚拟机所允许的深度。当然如果该区域扩展失败时也会抛出OutOfMemoryError。

本地方法栈

该区域跟Java虚拟机栈作用一样,不过执行的是Java中Native方法。也会StackOverflowError和OutOfMemoryError。

GC

垃圾回收有多种算法:标记-清除算法、复制算法和标记整理算法。每个算法怎么操作的网上都有一堆资料。这里不解释了。


JDK Tools

其实JDK自带了很多强大的工具,位于%JAVA_HOME%\bin 下,因此使用的时候要打开cmd然后进去该目录。

jps

jps -l

这样就可以查看本地所有java进程pid及名字


比如,本地weblogic的进程pid现在是 32020.

jstat

通过该命令可以查看某个进程的情况。

jstat -gc 32020 300 20
注意:这里 32020 是上边查到的pid,


jstack

该命令可以查看当前进程的栈情况

jstack -l 32020

JConsole

到了我们的工具重头戏了。上边提到的工具一方面都是 unsupport的,另一方面可读性都不是很好,且都是查看本地JVM。jconsole既能monitor本地JVM也能monitor远程JVM。

打开jconsole后,它会列出所有本地可用的JVM进程,选择一个即可连接。另外也可以指定host:port 去连接远程的JVM。

连接我本地的weblogic效果如下:


切换到Memory tab即可查看各个JVM内存区域的使用情况。另外也可以点击 "Perform GC",让JVM执行GC。这样就可以判断哪个内存区域在垃圾回收后依旧出现大量占用。



Monitor Tomcat

在tomcat中的目录中,打开bin/catalina.bat文件,在以下位置加上一句。

set JAVA_OPTS=-Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false


打开JConsole后,输入host,然后加上边设的8999即可。



Visualvm

Visualvm(多合一故障处理工具)可以说是JConsole的升级版,而且还可以安装一些插件,感觉更好用些。至少不用再去jre\lib\management 下面配置一些密码了。visualvm也是位于该目录下,双击jvisualvm.exe 即可打开。


JMeter

Apache JMeter是Apache组织开发的基于Java的压力测试工具。可以去官网下载,解压即可使用。

双击运行apache-jmeter-4.0\bin\jmeter.bat 即可启动。

使用JMeter分三步:创建请求线程组,设置监听器,执行请求并查看结果

创建请求线程组

在“Test Plan”(测试计划)上右键,创建一个 Thread Group


配置Thread Group的请求参数,并保存。


添加请求:这里我是测试一个Restful,使用HTTP Request。


同时指定要测试的URL,需要的话也可以添加参数:



设置监听器




执行请求并查看结果

点击执行,然后就可以查看测试结果了。



发布了96 篇原创文章 · 获赞 29 · 访问量 12万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章