- 浏览: 1283836 次
- 性别:
- 来自: 常州
-
文章分类
- 全部博客 (499)
- java (101)
- linux (82)
- mysql (30)
- javascript (45)
- Oracle (12)
- ext (14)
- 虚拟机 (1)
- 搜索引擎 (2)
- struts2 (11)
- 设计模式 (9)
- nginx (17)
- tomcat (12)
- 随想 (10)
- spring (18)
- svn (1)
- flash (3)
- UML (1)
- 数据结构 (7)
- 算法 (2)
- 网摘 (9)
- 数据库 (15)
- ibatis (3)
- jquery (31)
- lucene (1)
- hibernate (14)
- Myeclipse (4)
- 线程 (7)
- jbpm (4)
- 重构 (1)
- mantis (3)
- MediaWiki (4)
- ExtMail (1)
- MDaemon (1)
- egit (1)
- dwr (7)
- sitemesh (2)
- mybatis (1)
- ico (1)
- hadoop (5)
- jsoup (1)
- urlrewrite (2)
- jstl (1)
- spring3 (2)
- aop (2)
- 定时器 (1)
- Quartz (2)
- apache (1)
- php (1)
- security (1)
- iptables (2)
- QQ (1)
- mysqldump (1)
- vim (1)
- memcached (4)
- jad (1)
- 微博 (1)
- html5 (1)
- css3 (1)
- httpclient (10)
- google (1)
- shortUrl (1)
- json (2)
- virtualBox (1)
- mantisBT (2)
- htmlunit (1)
- selenium (2)
- mail (1)
- 正则表达式 (4)
- html (3)
- css (2)
- jatoolsPrinter (1)
- 图片处理 (1)
- hql (1)
- webservice (1)
- 分词 (3)
- 短信 (1)
- VPS (1)
- 事务 (1)
- 广告 (1)
- 画廊 (1)
- git (3)
- github (1)
- openshift (1)
- 缓存 (1)
- web (3)
- android (3)
- c3p0 (1)
- 邮箱 (1)
- memcache (2)
- windows (2)
- js (14)
- 编辑器 (1)
- 打印 (1)
- centos (5)
- boneCP (1)
- 连接池 (1)
- sql (1)
- nosql (1)
- MongoDB (1)
- 浏览器 (1)
- node (1)
- node.js (1)
- backbone.js (1)
- lazyload (1)
- Switch Off (1)
- Titanium (1)
- 网站架构 (1)
- WebDriver (1)
- APJP (1)
- 代理 (1)
- comet (1)
- kendoui (1)
- UI (2)
- 互联网 (1)
- localStorage (1)
- 记录 (1)
- 微信 (2)
- Sphinx (1)
- netty (1)
- js,mvvm,Avalon (1)
- 安卓 (1)
- Tengine (1)
- 大数据 (1)
- 手机 (1)
- paypal (1)
- SaaS (1)
- gitlab (1)
- nodejs (1)
- React (1)
- shadowsocks (0)
- vpn (0)
- 验证码 (1)
- SSL (2)
- SEO (1)
- IntelliJ (1)
- 敏捷开发 (1)
- 项目管理 (1)
- 爬虫 (1)
- 正则 (1)
- owncloud (1)
- 云存储 (1)
- ajax (1)
- pjax (1)
- jdk (1)
- zookeeper (1)
- phantomjs (1)
- ELK (1)
- springcloud (1)
- IDEA (1)
- hexo (1)
- ss (1)
- letencrypt (1)
最新评论
-
peakandyuri:
这个是有BUG的,数字小体现不出来,数字大了就不对了,但是Ja ...
java十进制转换N进制并反转换的工具类 -
ginolai:
然后是相关配置:/etc/sysconfig/iptables ...
Linux中iptables设置详细 -
bzhao:
我测试没啥区别啊!
Thread.sleep()和Thread.currentThread().sleep()区别 -
zhl549342097:
match == false
Spring Security 3.1 中功能强大的加密工具 PasswordEncoder -
hellotieye:
renzhengzhi 写道drager 写道用jsoup后解 ...
jsoup select 选择器
XSocket内存泄漏问题深度分析
大概一个月前在一个数据迁移的过程中,在数据迁移到900多W的时候程序崩溃了,系统最后记录的日志是这样的:
Exception in thread "xDispatcher#CLIENT" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:99) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288) at org.xsocket.connection.spi.AbstractMemoryManager.newBuffer(AbstractMemoryManager.java:219) at....... |
从
中不难看出这是xsocket的内存管理层程序通过JVM的nio创建DirectByteBuffer时抛出了错误。在这里先要说明一下的是,当时的系
统使用的xsocket2.0版,2.0版连接读取数据默认就是使用DirectByteBuffer的,目前2.4.X版已经默认都改为使用
ByteBuffer,而不再是DirectByteBuffer了。
DirectByteBuffer是由jvm调用jni程序在操作系统内存
中分配的空间的,不需要占用JVM的Heap Size。当程序需要读取Big Size或者Huge
Size数据的时候,使用DirectByteBuffer优势尤其明显。但使用DirectByteBuffer会产生一个问题,当JVM的空间还没满
但系统内存空间已经被消耗的差不多的时候,gc如何被触发呢。这个问题在一个叫Harmony的开源Java SE项目的mail
list中曾进行过热烈的讨论。参考资料1中有当时讨论过程的链接。
在跟踪JVM的一些源码后,发现,很庆幸,sun的jvm已经解决这个问题
了。但是对于尚不清楚其内存处理机制的开发人员来说。在使用DirectByteBuffer是还是很可能把系统置身于莫大的风险中。而很不幸这个问题隐
藏的相当的隐秘,对于不明就里的人,最后可能只好采取定时重启系统或者在系统中设定一些条件显式调用gc来曲线解决资源释放的问题。
题外话说了不少,下面我们直接从JVM的一些代码片段去分析文章最开始的Exception是在什么条件下引发的。首先我们来看看DirectByteBuffer的构建函数代码:
DirectByteBuffer(int cap) { super(-1, 0, cap, cap, false); Bits.reserveMemory(cap); int ps = Bits.pageSize(); long base = 0; try { base = unsafe.allocateMemory(cap + ps); } catch (OutOfMemoryError x) { Bits.unreserveMemory(cap); throw x; } unsafe.setMemory(base, cap + ps, (byte) 0); if (base % ps != 0) { // Round up to page boundary address = base + ps - (base & (ps - 1)); } else { address = base; } cleaner = Cleaner.create(this, new Deallocator(base, cap)); } |
注意以上片段中红色加亮的部分,然后我们再来看看Bits.reserveMemory这个方法的代码:
// -- Direct memory management -- // A user-settable upper limit on the maximum amount of allocatable // direct buffer memory. This value may be changed during VM // initialization if it is launched with "-XX:MaxDirectMemorySize=<size> ". private static volatile long maxMemory = VM.maxDirectMemory(); private static volatile long reservedMemory = 0; private static boolean memoryLimitSet = false; // These methods should be called whenever direct memory is allocated or // freed. They allow the user to control the amount of direct memory // which a process may access. All sizes are specified in bytes. static void reserveMemory(long size) { synchronized (Bits.class) { if (!memoryLimitSet && VM.isBooted()) { maxMemory = VM.maxDirectMemory(); memoryLimitSet = true; } if (size <= maxMemory - reservedMemory) { reservedMemory += size; return; } } System.gc(); try { Thread.sleep(100); } catch (InterruptedException x) { // Restore interrupt status Thread.currentThread().interrupt(); } synchronized (Bits.class) { if (reservedMemory + size > maxMemory) throw new OutOfMemoryError("Direct buffer memory"); reservedMemory += size; } } |
从
以上代码我们可以看到,JVM在通过DirectByteBuffer使用OS内存时(无论是分配还是释放),是有统计的,通过跟可使用的最大OS内存
(VM.maxDirectMemory())作比较,如果不够用,那显式调用gc,如果经过gc后还是没有足够的空分配内存,那么从Bit抛出
Exception。注意:这一步并未真正的像OS申请内存,只是VM通过计算得出的结论。而真正想OS申请内存是在
unsafe.allocateMemory这个方法里面通过JNI实现的。显然,文章最初的Exception是由Unsafe抛出而不是Bit抛出。
也就是说JVM认为OS还有足够的可分配内存,而当JVM真正向OS申请内存分配的时候却出错了。那么接下来我们就得看看,这个max direct
memory值是如何设定的。
现在我们看看VM.java的代码:
private static long directMemory = 67108864L;
... public static long maxDirectMemory() { if (booted) return directMemory; Properties localProperties = System.getProperties(); String str = (String)localProperties.remove("sun.nio.MaxDirectMemorySize"); System.setProperties(localProperties); if (str != null) if (str.equals("-1")) { directMemory = Runtime.getRuntime().maxMemory(); } else { long l = Long.parseLong(str); if (l > -1L) directMemory = l; } return directMemory; } |
可以看出来,max direct memory可以有三种值:
1)默认值,64M;
2)maxMemory,也就是通过-Xmx设定的值,默认也是64M;
3)通过-XX:MaxDirectMemorySize=<size>指定的值;
问
题到这里基本就是水落石出了,当时系统启动的时候设定-Xmx2048M,未指定MaxDirectMemorySize,也就是说max direct
memory被认为是2048M,整个系统的物理内存为4G,除掉系统进程占用的内存,剩下的物理内存加上swap空间也就接近3G。设想JVM的
heap size占用了1.5G,direct memory使用了1.5G,这时候程序申请一200M的direct内存,在这种情况下无论是JVM
heap size还是direct memory不满足触发gc的条件,于是jvm向os申请分配内存,OS无可分配的内存了就会抛出OOM错误。
补
充说明一下:在OS已经把物理内存+Swap都耗光都不足够分配内存空间的时候,不同OS可能会有不同的表现。LInux的内核有可能会尝试努力腾出更多
的内存空间。可能会杀掉某些进程。(这是参考资料一中Ivan
Volosyuk所提出来的问题)。而我在使用以下程序进行测试时,出现整个OS系统假死的状况,过一段时间回复过来了。但整个过程可以肯定的一件事是
gc始终没有被触发到。
以下是我用来验证我的以上分析的测试程序:
import java.lang.management.ManagementFactory; import java.nio.ByteBuffer; import java.util.logging.Logger; import com.sun.management.OperatingSystemMXBean; public class TestMemoryLeak { private static Logger logger = Logger.getAnonymousLogger(); public static void main(String[] args) throws Exception{ OperatingSystemMXBean osmb = (OperatingSystemMXBean) ManagementFactory .getOperatingSystemMXBean(); System.out.println("Total physic memory:" + osmb.getTotalPhysicalMemorySize() / 1024 / 1024 + "MB"); System.out.println("Free physic memory:" + osmb.getFreePhysicalMemorySize() / 1024 / 1024 + "MB"); System.out.println("Max memory:" + Runtime.getRuntime().maxMemory()); System.out .println("Total memory:" + Runtime.getRuntime().totalMemory()); System.out.println("Free memory:" + Runtime.getRuntime().freeMemory()); System.out.println("===================================="); //testDirectByteBuffer(); testByteBuffer(); System.out.println("===================================="); System.out.println("Free physic memory:" + osmb.getFreePhysicalMemorySize() / 1024 / 1024 + "MB"); } public static void testDirectByteBuffer(){ try{ ByteBuffer bb1 = ByteBuffer.allocateDirect(1024 * 100000 * 4); bb1 = null; System.out.println("Free memory:" + Runtime.getRuntime().freeMemory()); ByteBuffer bb2 = ByteBuffer.allocateDirect(1024 * 100000 * 5); bb2 = null; System.out.println("Free memory:" + Runtime.getRuntime().freeMemory()); //System.gc(); //pause expect for gc Thread.sleep(1000*6); ByteBuffer bb3 = ByteBuffer.allocateDirect(1024 * 100000 * 8); System.out.println("Free memory:" + Runtime.getRuntime().freeMemory()); }catch(Exception e){ e.printStackTrace(); } } public static void testByteBuffer(){ try{ ByteBuffer bb1 = ByteBuffer.allocate(1024 * 100000 * 4); bb1 = ByteBuffer.allocate(1024 * 10 * 4); System.out.println("Free memory:" + Runtime.getRuntime().freeMemory()); ByteBuffer bb2 = ByteBuffer.allocate(1024 * 100000 * 3); bb1 = ByteBuffer.allocate(1024 * 10 * 3); System.out.println("Free memory:" + Runtime.getRuntime().freeMemory()); //System.gc(); //pause expect for gc Thread.sleep(1000*6); ByteBuffer bb3 = ByteBuffer.allocate(1024 * 100000 * 6); System.out.println("Free memory:" + Runtime.getRuntime().freeMemory()); }catch(Exception e){ e.printStackTrace(); } } } |
程序启动需用如下命令:
java -verbose:gc -Xms64M -Xmx512M -XX:MaxDirectMemorySize=1000M TestMemoryLeak
-verbose:gc用于开启gc运行情况的输出,可以帮助我们了解jvm垃圾收集的运作情况;
其他参数值应该你机器的实际情况设定。
最后我想总结的是,当我们在使用DirectByteBuffer的时候一定要注意:
1)谨慎设定JVM运行参数,最好用-XX:MaxDirectMemorySize进行设定,否则你就得清楚你设定的mx不单单制定了heap size的最大值,它同时也是direct memory的最大值;
2)在密集型访问中(例如数据迁移工具)适当增加对gc的显式调用,保证资源的释放;
参考资料:
[VM]How to trigue GC while free native memory is low.
发表评论
-
[转]Spring Cloud微服务的那点事
2018-04-20 21:58 697转自:https://blog.csdn.ne ... -
[转]ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平台
2018-04-20 17:10 901本文转自:https://my.oschin ... -
生成无重复的hashid短地址(短随机字符串)
2017-04-26 14:57 2225具体查看项目: http://hashids.org/j ... -
2017年Struts漏洞修复:版本从2.3.15.1升级到2.3.32
2017-03-24 15:10 2039如果你当前的项目使用了Struts2.3.5至 Strut ... -
多线程爬虫Miner [转]
2016-08-01 13:49 855多线程爬虫Miner 本文转自原作者博客:http:/ ... -
JAVA关键字替换
2015-11-03 21:22 1071import java.util.ArrayList; ... -
关于java web前后端分离
2015-08-27 22:47 1955由于公司架构上需要前后端分离,这里先记录一下相关内容,待后 ... -
基于NODEJS的前后端项目分离实践
2015-06-17 14:07 1215前后端分离项目实践 本文转自:http://jiangxi ... -
paypal IPN返回
2015-05-28 10:12 20891.设定返回的地址 目标:登录paypal-->用户 ... -
根据class搜索jar包
2015-05-20 13:00 903http://grepcode.com/ -
基于DWR的点对点聊天实现 server---client
2015-04-28 16:53 1193本文转自:http://htj1231825.iteye.c ... -
Java分布式中文分词组件word分词v1.2发布
2015-04-20 12:07 822word分词是一个Java实现的分布式的中文分词组件,提供了 ... -
java开源论坛jeebbsV4发布
2015-04-08 09:56 633论坛APP的帖子新展现形式 APP即时聊天模块 ... -
开源大数据解决方案
2015-03-12 13:01 1092解决方案 开发商 类型 描述 Storm Twit ... -
根据用户IP查询所属国家(数据库版)-geoip
2015-03-06 14:44 1211关键词:geoip,最新版本GeoIP2 http:// ... -
查询用户IP所在地服务接口(淘宝)
2015-03-04 10:17 1095import java.io.BufferedReader; ... -
java内存溢出优化
2014-12-28 12:42 2235本文转自:http://www.importnew.com ... -
Tomcat6线程池(Executor Thread pool)的配置
2014-12-27 01:07 938原文地址:http://www.java2000.net/p ... -
Netty学习系列导航-开源Java高性能NIO框架推荐
2014-08-13 17:49 1376纯记录,事件驱动服务器和客户端设计: http://mus ... -
破解验证码相关:用imagemagick和tesseract-ocr破解简单验证码
2014-08-13 17:08 2973本文源自:http://hooopo.iteye.com/ ...
相关推荐
### Tomcat 6.0 修改启动内存设置及 Java JVM 参数配置详解 #### 一、背景与目的 在部署和运行 Java Web 应用时,合理地配置应用服务器(如 Apache Tomcat)的内存是非常重要的。这不仅可以提升应用程序的性能,还...
JVM 内存溢出问题解析 JVM 内存溢出是指程序运行所需的内存大于虚拟机能提供的最大内存的情况。这种情况可能是由于数据量过大、死循环、静态变量和静态方法过多、递归、无法确定是否被引用的对象等原因引起的。同时...
默认情况下,Tomcat的JVM内存设置可能无法满足所有应用程序的需求,特别是在资源密集型应用或高并发场景下。因此,了解如何手动调整Tomcat的JVM内存设置至关重要。 #### 二、理解JVM内存模型 在深入探讨如何设置...
根据提供的描述“myeclipse-tomcat jdk内存溢出,针对myeclipse做的相应的配置”,我们可以了解到该问题是由于MyEclipse中Tomcat服务器所使用的JDK设置不当导致的JVM内存不足。接下来,我们将详细探讨这一问题的具体...
3. **配置不当**:在配置文件中,如果没有正确地设置JVM参数来调整内存大小,也会导致内存溢出。 #### 三、解决内存溢出问题的方法 针对上述问题,我们可以采取以下措施来解决Eclipse中Tomcat启动时遇到的内存溢出...
### Eclipse + Tomcat 内存溢出参数设置详解 在Java开发过程中,特别是在使用Eclipse作为集成开发环境(IDE)并结合Apache Tomcat服务器进行Web应用开发时,经常会遇到内存溢出的问题。这类问题通常表现为应用程序...
为了解决Tomcat内存溢出问题,主要是加大Tomcat可利用内存,并在程序当中加大内存使用。具体解决方法如下: 1. 加大Tomcat可利用内存: 在Tomcat的目录下,也就是在Tomcat41/bin/catalina.bat文件最前面加入set ...
标题中的“关于tomcat乱码以及tomcat jvm 内存溢出问题的解决方案和理论”涉及了两个关键的IT概念:Tomcat服务器的字符编码问题和Java虚拟机(JVM)内存管理的问题。让我们逐一深入探讨这两个主题。 首先,我们来...
#### 二、JVM内存参数设置 ##### 1. Linux下的Tomcat JVM内存设置 在Linux环境中,Tomcat的JVM内存设置需在`bin/catalina.sh`文件中进行,具体操作是在`cygwin=false`行前添加或修改JVM参数。关键参数包括: - `-...
1. **调整JVM参数**:在Tomcat的启动脚本(如`catalina.sh`或`catalina.bat`)中,可以通过设置JVM的启动参数来控制内存大小。常用的是-Xms和-Xmx参数,分别代表初始堆内存和最大堆内存。例如,可以设置为`-Xms256m ...
Tomcat内存溢出的三种情况及解决办法分析 Tomcat内存溢出是指Tomcat服务器在运行过程中无法分配足够的内存空间...Tomcat内存溢出是由于内存空间不足所致,解决方案是调整参数和调整操作系统和Tomcat JVM参数同时调整。
【标题】"Tomcat JVM参数调优"涉及的是在运行Apache Tomcat服务器时优化Java虚拟机(JVM)性能的过程。Tomcat是一个流行的开源Java应用服务器,它用于部署和运行Java Servlets和JavaServer Pages(JSP)。由于JVM是...
### Tomcat设置服务启动参数详解 #### 一、引言 Apache Tomcat 是一款开源的Servlet容器,主要用于部署和运行Java Web应用。为了确保Tomcat能够高效稳定地运行,合理配置其启动参数至关重要,尤其是与内存相关的...
当使用Tomcat部署Java应用程序时,也可以通过调整Tomcat的JVM参数来优化内存配置。 1. 打开Tomcat的安装目录下的`bin`文件夹,找到`catalina.bat`文件。 2. 在文件顶部添加以下配置: ``` set JAVA_OPTS=-Xms1024...
Tomcat7 安装使用及 JVM 连接数参数调优 Tomcat7 是一个流行的 Java Web 服务器,主要用于部署和管理基于 Java 的 Web 应用程序。为了确保 Tomcat7 的稳定运行和高效性能,需要对其进行合理的安装、配置和优化。...
Tomcat内存溢出问题虽然常见,但通过合理调整JVM参数、优化代码以及合理配置操作系统参数等方式,完全可以有效地解决这些问题。此外,持续监控和适时优化也是预防内存溢出的关键步骤。希望以上内容能够帮助开发者们...
在IT领域,特别是Java应用服务器的管理与优化中,合理设置Tomcat的内存参数是确保应用稳定运行的关键步骤之一。本文将围绕“设置Tomcat启动内存大小”这一主题,深入探讨如何通过修改配置文件来调整Tomcat服务器的...
特别是在大数据处理场景下,合理设置JVM内存参数显得尤为重要。本文将深入探讨JVM内存管理的基础概念、内存设置方法及其调优策略,以帮助开发者避免常见的`java.lang.OutOfMemoryError`异常,提升应用性能。 #### ...
在 MyEclipse 中,我们可以在 Tomcat 启动参数中添加 `-Xms168m -Xmx512m` 参数来解决内存溢出问题。 PermGen Space PermGen Space 是 JVM 的永久保存区域,主要存放 Class 和 Meta 信息。 PermGen Space 的大小是...
- 在日常开发中,应当注重代码优化,避免不必要的内存消耗,同时合理设置 JVM 参数以防止内存溢出的发生。 综上所述,正确使用 MAT 分析工具不仅能够帮助我们解决问题,还能提高开发效率和代码质量。希望本文对面临...