64位指针膨胀 java_Java 程序优化知识笔记

19fd0000849b2487be0a.jpg

19fa0002356bcd1b6d86.jpg

迁移 64 位虚拟机未必性能更好

业务量上升以后,需要使用的内存随之增加,而在通常 32 位系统上,单个进程占用的最大内存通常是 2GB,且考虑到堆外内存的使用,32 位机器可能无法满足内存要求,一种常见的应对方式就是换用 64 位服务器。而对于 Java,由于指针膨胀和字节对齐,同一个程序在 64 位虚拟机上占用的内存会多于 32 位虚拟机。开发者换用 64 位虚拟机后,很可能会增加虚拟机的堆大小,而这将导致 Full GC 垃圾回收的时间大大增加,导出堆快照也变得困难。

因此,使用 64 位虚拟机增加内存时,需要特别注意对内存的使用,尽量不要触发 Full GC 导致长时间停顿。另一种方法是建立 32 位虚拟机的集群来提高性能。

堆外内存溢出

Java 本地方法调用,如调用 C++ 实现的本地模块、NIO 的 DirectByteBuffer,都会占用大量内存。而在开发中,开发者往往重点关注了堆内存的大小,在内存溢出时也倾向于增加堆内存,而忽视了堆外内存的使用。堆外内存并不会像堆内存一样不足马上通知 GC 进行垃圾回收,堆外内存只能等待老年代空间不足进行 Full GC 时顺便回收内存,否则堆外内存只能等到空间不足时抛出内存溢出异常,然后请求 GC 进行回收。

因此,配置虚拟机,除考虑常规的堆大小外,优化时还需要考虑 Direct Memory、线程栈、socket 缓冲区、JNI 代码、虚拟机、GC 占用的内存大小。

外部命令的时间消耗

Java 开发中如果需要执行 shell 脚本,可以使用 Runtime.getRuntime().exec 方法,还能从返回的 Process 对象中读取标准输出、错误输出、等待执行结束。根据方法注释,该方法首先复制当前进程产生一个子进程,在子进程中执行命令,结束后退出子进程。

进程的复制比较消耗 CPU 和内存,应尽量通过 Java 程序本身去完成相关功能。

多线程使用线程池

Java 虚拟机中没有给用户用的多进程方法,并行处理更多地使用多线程方式。默认情况下,Linux 限制用户的线程数量上限为 1024,当然包括了系统中运行的所有线程。通常情况下,线程资源不会被耗尽,但多线程程序如果频繁创建新线程也会遇到线程资源不足的情况。一方面,可以调整系统设置,提高线程数上限,另一方面,应尽量避免频繁创建线程。线程虽小,创建时一样要消耗时间和内存。

多线程程序应尽量采用 Java 的线程池,这样线程的个数总体可控,使用时可以避免创建线程的时间消耗。Java 提供了多种功能强大的线程池类型,基于线程池可以对任务进行缓存、按照一定的时间频率执行任务、返回执行结果、分叉与合并等。

每周 3 篇学习笔记或技术总结,面向有一定基础的 Java 程序员,内容涉及 Java 进阶、虚拟机、MySQL、NoSQL、分布式计算、开源框架等多个领域。关注作者或微信公众号 backend-develop 第一时间获取最新内容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值