JVM-调优 / Linux命令

963 阅读6分钟

问Linux命令的时候,不是列出这些命令,而是说当时在解决什么问题时用的这个命令。

OOM发生场景,反映到JVM内部是怎么样的

SOF(java.lang.StackOverflowError):

while导致方法栈溢出、递归调用太深导致栈溢出。

函数内的数组过大,导致栈溢出。

OOM(java.lang.OutOfMemoryError):

1.Java Heap space

堆内存不足以存放新创建出的对象、堆内存使用量达到最大内存限制、内存泄露逐渐堆积。比如缓存在内存中存储,我们提前对数据库中的用户进行全量存储,为了方便查找放在Map中。但现在有这么一个需求,需要下拉立即显示模糊的用户名。那么每一级的key都会对应很多用户名,这些都需要一个单独的Map存储,就可能撑爆内存发生OOM。所以我们可以使用key+Set,过滤掉每一级多余的用户名,减少对象的数量。

解决:增大堆内存空间

2.GC overhead limit exceeded

Executors.newFixedThreadPool提供的线程池默认的任务队列无界,所以队列可能快速挤压,撑爆内存导致OOM.

3.Direct buffer memory(直接内存溢出):

NIO的ByteBuffer.allocateDirect(capability)方法:使用JVM堆内存外的本地内存进行数据拷贝。没有使用JVM所以不触发GC,对象不被回收,时间久了本地内存就会被用完,就会出现OutOfMemoryError。

解决:手动释放buffer、增大本地内存

4.unable to create new native thread

Executors.newCachedThreadPool提供的线程池,它的最大线程数是没有上限的,而它默认使用SynchronousQueue无存储空间的阻塞队列,也就意味着只要有请求到来就需要有线程来执行,即会无限创建大量的线程导致OOM。

解决:降低线程数、修改服务器线程上限配置

5.Metaspace(元空间):

就是方法区呀,存放类信息、常量池、静态变量。元空间满了就报此异常

内存泄漏和内存溢出

内存泄漏是指不再使用的对象没有被及时回收,持续占用内存而造成的空间浪费。

new subString()会调用new String(),利用到原来的字符串。但如果subString只使用了String中的一小段,而String字符串不再被使用,此时String字符串被subString引用而无法回收,造成内存泄露 内存溢出是发生OOM,垃圾回收的速度跟不上场景对象的速度。

JVM参数与命令

-xms、-xmx、-xss分别代表了什么?为什么要有这些参数

-Xms:指定程序启动时申请的内存空间大小,也就是创建进程时需要的Java堆大小。当初始内存不够时会自动扩容。

-Xmx:指定程序运行时最大可占用的内存大小。

-Xss:指定每个线程的堆栈大小(堆内存设置过大:寻址开销变大,增加JVM的负载。

64G内存的机器,JVM参数如何配置:

JVM的初始-xms默认是物理内存的1/64,-xmx默认是物理内存的1/4.当默认空余堆内存小于40%时,JVM会增大堆直到-xmx;当空余堆内存大于70%时,JVM会减少堆直到-xms。所以服务器一般设置-xms与-xmx相等,避免每次GC后都要调整堆。32位系统的可控内存空间有4G,所以限制为2G-3G。

查看JVM参数:ps得到进程id,jmap -heap pid查询到JVM配置信息(包括垃圾收集器类型)

JVM有哪些参数可以设置

①执行时:-Xms指定堆初始大小、-Xms指定堆最大值、-Xss每个线程的堆栈大小

②-XX:+Use...GC:指定使用的GC类型。

③开启G1:-XX:UseG1GC

④设置GC最大停顿时间(G1的预期停顿时间):-XX:MaxGCPauseMills

⑤直接内存大小:-XX:MaxDirectMemorySize

⑥打印GC日志:见下面

Java排查性能问题的参数

①top:实时显示各个进程的CPU占用率、内存使用率等资源占用情况。

②top -Hp pid:查看具体线程的CPU占用率。

③vmstat:可以指定采样周期和次数的监测工具,可以用来查看上下文切换次数

④jstat:查看堆内存信息和GC信息。jstat -gc显示GC相关的堆信息、jstat -gcutil显示GC信息。它会打印各个元区使用量和GC次数。

⑤jstack:查看线程的堆栈信息。

⑥jmap:输出堆内存的对象信息

查看GC信息:

①jstat -gcutil pid {时间间隔}:显示各个元区的占用百分百与GC次数。

②-XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/log/heapTest.log:将运行时的GC日志dump下来。

排查问题

www.cnblogs.com/sreops/p/14…

CPU 100%处理过程:

①通过top命令找到占用CPU最高的进程pid

②通过top -Hp pid找到进程中占用CPU过高的线程tid

③通过jstack pid | grep tid {-A 30} 得到线程堆栈信息,根据堆栈信息就可以定位到项目中的问题了。

排查OOM内存溢出:

①配置JVM启动参数-XX:HeapDumpOnOutOfMemoryError与-XX:HeapDumpPath,JVM发生OOM时就会自动生成dump日志

②使用 jmap -dump:format=b , file=D:\test\heap.hprof 6956导出dump日志(进程号:netstat -ano | find “8080” 查看当前应用程序使用的进程号。)

③可以使用JDK自带的jvisualvm导入dump快照,进行查看。

排查内存泄露

内存泄露有可能会引发频繁的full GC,所以可以用jstat -gcutil查看GC相关信息。

内存泄露可能会引发内存溢出,所以见上。

Linux命令

查看所有正在运行的Java程序:ps -aux | grep java

awk:awk '{print 0}' (0整行,$1第一个字段)

查看倒数第二列,查看第10-20行

tail -n 2

head -20 a.txt | tail -11

head -n 100 显示前100行,tail -n 100 从100行开始显示后面的。

top:实时显示各个进程的资源占用情况,如CPU利用率、cpu平均负载等。

cpu使用率:单位时间内,CPU的繁忙情况

cpu平均负载:单位时间内,系统中处于可运行状态、休眠但不可中断状态的平均进程数。

如何查看端口:netstat -anp

chmod:r4代表可读,w2代表可写,x1代表可执行

Linux查找某个目录下匹配的文件名

find . -name 'xxx'

grep -rnl 'xxx' 递归查找、不显示行号、只输出文件名 Linux查找某个目录下含有某字符串的文件名 find .|xargs grep -ri 'xxx' -l ,-i不区分大小写、-l只输出文件名

查找文件中含有xxx字符串的行

sed -n '/xxx/p' a.txt

more分页查询(空格向下、ctrl+B向上一屏)

  1. (工具网址:chrome-error://chromewebdata)
  2. 查找文件
    1. -i:搜索时忽略大小写
    2. Find /home  -name "*log":查找home目录及其子目录下以“log”结尾的文件。
      1. | xargs grep “xxx” 判断日志中是否有内容xxx,返回true false
        • type f是文件、-type d是目录
    3. Find . -iname   a.txt -o -iname b.txt:忽略大小写,查找当前目录下的a.txt和b.txt
    4. Find . -maxdepth n -type f:指定搜索深度打印出当前目录的文件。
    5. Find . - type -name “*.swp” -delete:删除当前目录下的所有swap文件。
  3. 文本搜索grep,用于过滤:
    1. grep附加的常用参数:
      1. -o :输出匹配的文本行
      2. -v:输出不匹配的文本行
      3. -c:统计次数
      4. -n:附带输出匹配的行号
      5. -R:递归多级子目录
      6. -e: “xxx” -e ”xxx” or的作用
      7. 其中’xxx’可以是正则表达式
        1. [gd] == g??d
        2. g..d==g??d
        3. ^xxx:以xxx开头
        4. xxx$:以xxx结尾
    2. 查找带where条件的sql语句:
  4. Tail查看文件
    1. Tail  -n 10 文件路径:查看文件的最后10行(加上-f 是查看实时日志)
    2. Tail -n +10 文件路径:查看文件的最前10行之后的所有日志
    3. Head -n 10 文件路径:查看文件的最前10行
  5. awk
    1. | awk ‘/.../‘:可以用正则表达式指定条件,可以用循环
    2. 正则表达式:%s、print 1:1:2
  6. 场景1:查看某关键字附件的日志
    1. 得到关键字处于的行号:Cat -n aaa.log | grep “你好” 
    2. 查看关键字的前后10行:cat -n aaa.log | tail  +10 | head -n 20
    3. 得到关键字行号后,根据基本tail命令查看行号前后的日志
  7. 场景2:按日期时间查找日志
    1. Sed -n ‘/日期/p’ aaa.log
  8. 场景3:前面得到的日志文件过多?
    1. | less:分页(b是向前翻一页,空格是向后翻一页)
    2. xxx.txt:输出到文件中

  9. 正则:
    1. 正则方式查找.txt和pdf:find . -regex  “.*(.txt|.pdf)$”