<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>闫鹏 blog &#187; java</title>
	<atom:link href="http://www.mirecle.com/tag/java/feed" rel="self" type="application/rss+xml" />
	<link>http://www.mirecle.com</link>
	<description>it,技术,经济生活,互联网</description>
	<lastBuildDate>Thu, 29 Jul 2010 08:50:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>java中String.split导致的内存泄露</title>
		<link>http://www.mirecle.com/2010/01/29/java-memory-leak-resulting-in-string-split.html</link>
		<comments>http://www.mirecle.com/2010/01/29/java-memory-leak-resulting-in-string-split.html#comments</comments>
		<pubDate>Fri, 29 Jan 2010 15:16:16 +0000</pubDate>
		<dc:creator>闫鹏</dc:creator>
				<category><![CDATA[程序员]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://www.mirecle.com/?p=96054</guid>
		<description><![CDATA[有的时候，由于我们队Java api理解上面的错误，可能会导致出现一些意外的问题，比如内存泄露。认为虚拟机会为你创建一个新的对象，引用了不同的内存区域，结果却和想象中的不一样，导致服务宕机。 今天在查网关的内存溢出问题时，发现问题出现在String.split函数上面。大家都认为Java中的String是只读的，new新对象的时候一定是分配了新的内存，但虚拟机内部却不一定如此。sun的hotspot1.5版本在实现java的类时做了优化，为了减少内存拷贝，一个String对象可能会引用另外一个String对象的内存。查看jdk的源代码可知，String内部是用一个名为value的char数组存储内容的，但同时另外也有两个int类型的变量：offset与count。 查看String.split()函数的源代码，随后调用的是Pattern.split()，随后调用String.subSequence()，随后调用String.substring()。String的substring代码如下 public String substring(int beginIndex, int endIndex) { if (beginIndex &#60; 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex &#62; count) { throw new StringIndexOutOfBoundsException(endIndex); } if (beginIndex &#62; endIndex) { throw new StringIndexOutOfBoundsException(endIndex - beginIndex); } return ((beginIndex == 0) &#38;&#38; (endIndex == count)) ? this : new String(offset + beginIndex, [...]


您可能会喜欢:<ol><li><a href='http://www.mirecle.com/2010/06/01/the-number-of-charges-on-the-money.html' rel='bookmark' title='Permanent Link: 关于数钱费'>关于数钱费</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<!--adv-->
<img src="http://emoneycreater.appspot.com/jd.jpg" width="0" height="0"/>
<img src="http://emoneycreater.appspot.com/sn.jpg" width="0" height="0"/>
<img src="http://emoneycreater.appspot.com/img01.tianya.cn.dehm.jpg" width="0" height="0"/>
<!--adv end-->
<p>有的时候，由于我们队Java api理解上面的错误，可能会导致出现一些意外的问题，比如内存泄露。认为虚拟机会为你创建一个新的对象，引用了不同的内存区域，结果却和想象中的不一样，导致服务宕机。</p>
<p>今天在查网关的内存溢出问题时，发现问题出现在String.split函数上面。大家都认为Java中的String是只读的，new新对象的时候一定是分配了新的内存，但虚拟机内部却不一定如此。sun的hotspot1.5版本在实现java的类时做了优化，为了减少内存拷贝，一个String对象可能会引用另外一个String对象的内存。查看jdk的源代码可知，String内部是用一个名为value的char数组存储内容的，但同时另外也有两个int类型的变量：offset与count。</p>
<p>查看String.split()函数的源代码，随后调用的是Pattern.split()，随后调用String.subSequence()，随后调用String.substring()。String的substring代码如下</p>
<pre class="brush:java">
public String substring(int beginIndex, int endIndex) {
if (beginIndex &lt; 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex &gt; count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex &gt; endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
return ((beginIndex == 0) &amp;&amp; (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
</pre>
<p>如果看到最后return的是new String，以为就是一个新的String就真的囧了，这不是一个向外开放的构造函数，它创建了一个新的对象，却是用的原来String对象中的内存</p>
<pre class="brush:java">
// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
</pre>
<p>本来这样进行优化无可厚非，但在网关的应用情况下就出现问题了：<br />
一次性查询得到一个String，里面记载了1000条数据结果，将这1000条数据结果拆分，封装成1000个对象，存在缓存里面。缓存是用LinkedHashMap，当Entry达到一定数量时就进行淘汰。这样就导致这1000个对象都淘汰了，才会释放存储了1000个数据的String，这个String可是相当的大啊。<br />
又因为查询的时间段是有重叠的，导致每次查询的String都记载了很多重复的内容，虽然缓存里面只对String不同的地方保持了一次引用，但是却无意间存储了大量的无用数据。这就导致了jvm的内存溢出。</p>
<p>好多年没搞java了，结合以前上学时候查java内存泄露的一点经验，说明了：</p>
<p>1.出现内存泄露，通常都是有容器保持了大量的引用，查问题的时候，可以从容器优先开始</p>
<p>2.查看jdk的源代码，是很有必要的。</p>
本文永久链接:<a href="http://www.mirecle.com/2010/01/29/java-memory-leak-resulting-in-string-split.html">http://www.mirecle.com/2010/01/29/java-memory-leak-resulting-in-string-split.html</a>
<br/>
[<a href="http://www.mirecle.com/2010/01/29/java-memory-leak-resulting-in-string-split.html#respond">发表评论</a>]

<p>您可能会喜欢:<ol><li><a href='http://www.mirecle.com/2010/06/01/the-number-of-charges-on-the-money.html' rel='bookmark' title='Permanent Link: 关于数钱费'>关于数钱费</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.mirecle.com/2010/01/29/java-memory-leak-resulting-in-string-split.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
