java特种兵读书笔记(3-6)——java程序员的OS之JAVA常用工具

jps


jps过滤出java本身的进程以及运行的引导类(即引导的Main方法所在的类)。

$ sudo jps -l
26513 sun.tools.jps.Jps
8538 org.apache.catalina.startup.Bootstrap

两个进程,jps本身的进程,还有tomcat的Bootstrap的容器引导类。

jps命令也是基于java实现的。

jstat


sudo jstat -gcutil <pid>1s

pid是进程号,1s代表一秒钟,如果不写单位,默认单位是ms,1000代表一秒。

S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 37.79 61.51 22.94 20.85 17839 248.930 25 4.500 253.430
0.00 37.79 77.48 22.94 20.85 17839 248.930 25 4.500 253.430
0.00 37.79 92.47 22.94 20.85 17839 248.930 25 4.500 253.430
57.15 0.00 11.58 23.05 20.85 17840 248.938 25 4.500 253.438

从左到右依次是,两个Survivor区,Eden区,Old区,PermGen区,YoungGC次数,YoungGC时间,FullGC次数,FullGC时间,GC总时间。

jmap


sudo jmap -heap <pid>

查看堆信息,包括堆使用情况。

sudo jmap -histo <pid>

输出活着的对象数和大小。

jmap -dump:format:b,file: heap.bin <pid>

结果可以用MAT工具来分析。

jmap的一个坑是当用它来dump内存的时候,系统会暂时停止(因为要保证拷贝过程中内存没有变化)。它会先做一次FullGC,比GC的时间更长。其次dump下来的文件很大,普通机器没法跑起来。

注意:如果不加-u tomcat会报错,8538: well-known file is not secure,因为这个应用是另一个用户启动的(tomcat),所以用root权限无法做该操作。

jstack


用于输出线程信息,我们主要关注线程的状态。

sudo -u tomcat jstack -l <pid>

"shared-sched-thread-4" daemon prio=10 tid=0x00007f8e10008800 nid=0x21be waiting on condition [0x00007f8e71fde000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007826ffc40> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1085)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)

Locked ownable synchronizers:
- None

"shared-sched-thread-4":ThreadName prio(线程优先级)

tid(线程在heap区域的Thread对象地址)

nid是线程的ID

State表示线程状态(有RUNNABLE,BLOCKED,WAITING,IN_NATIVE等等)。

注意:如果不加-u tomcat会报错,8538: well-known file is not secure,因为这个应用是另一个用户启动的(tomcat),所以用root权限无法做该操作。

jinfo


jmap可以看内存使用基本信息,jinfo可以看更详细的配置。

案例


一个单例模式的instance,在该instance中有一个map做的cache。因为单例,那么这个instance引用永远不会被回收,那么里面的map做的cache也不会被回收(除非被替换了),然后向这个map中填充数据的话,map就会越来越大,最后撑爆内存。

首先用HashMap做缓存,在多线程是不靠谱的,应该用ConcurrentHashMap。

首先是并发可见性问题,其次是内在判定修改动作导致的RaceCondition,容易出现丢数据甚至是死循环现象。在多线程对这种非线程安全的集合类同时做写操作时,会有Concurrent ModificationException。

可以考虑分布式缓存(redis),guava的cache,可以设置最大容量。

现代的JVM本省并不是一个适合存储大量数据的地方,将大量数据cache在内存中是很古老的方式。

凡事无绝对,如果为了“小而美”,每次需要一个东西都要通过IO去读取一次数据(而不考虑本地缓存或者缓冲区),批处理读取的东西拆成一条一条,会适得其反。

鸡精


当程序可控时,申请更少内存可以解决的问题就不要申请更多内存,但也不要为了一点点内存让代码丑陋。

遇到大数据处理,尝试分段解决。

大量小IO操作,合并成一个批处理。

局部代码遇到大对象,而且该对象的后续代码要执行很长时间,但并不会用到该对象,可以手工将对象置位null,帮助GC很快的认为它是垃圾。但是当代码跑的很快,大对象可以快速脱离作用域,这种情况置null就没有必要了。

程序中有很多内存在程序中跑的时候,尽量缩小其作用域,尤其不要把他们放在寿与天齐的对象(通常指static),以及长命百岁的对象(session,而且session过期时间很长)。

当在实际应用中确定某些内存很常用,不会改变,但加载到内存代价很大,可以考虑在程序启动时将数据填充好。

内存中有cache的时候就不要自己new对象了,尤其Integer这种自动拆箱装箱的。

遇到反复叠加数据(字符串叠加,结合类叠加),尝试用一个外部引用变量或者对象来进行操作,是为了让整个叠加过程产生的碎片非常少。因为无论

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值