java优化技巧_Java 性能优化手册:提高 Java 代码性能的各种技巧

Java7u40 版本扩展了字符串池的大小(这是组要的性能更新)到 60013.这个值允许你在池中包含大约 30000 个独立的字符串。通常来说,这对于需要保存的数据来说已经足够了,你可以通过 -XX:+PrintFlagsFinal JVM 参数获得这个值。

我尝试在原始发布的 Java 8 中运行相同的测试,Java 8 仍然支持 -XX:StringTableSize 参数来兼容 Java 7 特性。主要的区别在于 Java 8 中默认的池大小增加到 60013:

50000; time = 0.019 sec

100000; time = 0.009 sec

150000; time = 0.009 sec

200000; time = 0.009 sec

250000; time = 0.009 sec

300000; time = 0.009 sec

350000; time = 0.011 sec

400000; time = 0.012 sec

450000; time = 0.01 sec

500000; time = 0.013 sec

550000; time = 0.013 sec

600000; time = 0.014 sec

650000; time = 0.018 sec

700000; time = 0.015 sec

750000; time = 0.029 sec

800000; time = 0.018 sec

850000; time = 0.02 sec

900000; time = 0.017 sec

950000; time = 0.018 sec

1000000; time = 0.021 sec

Java虚拟主机上测试代码

这篇文章的测试代码很简单,一个方法中循环创建并保留新字符串。你可以测量它保留 10000 个字符串所需要的时间。最好配合 -verbose:gc JVM 参数来运行这个测试,这样可以查看垃圾收集是何时以及如何发生的。另外最好使用 -Xmx 参数来执行堆的最大值。

这里有两个测试:testStringPoolGarbageCollection 将显示 JVM 字符串池被垃圾收集 — 检查垃圾收集日志消息。在 Java 6 的默认 PermGen 大小配置上,这个测试会失败,因此最好增加这个值,或者更新测试方法,或者使用 Java 7.

第二个测试显示内存中保留了多少字符串。在 Java 6 中执行需要两个不同的内存配置 比如: -Xmx128M 以及 -Xmx1280M (10 倍以上)。你可能发现这个值不会影响放入池中字符串的数量。另一方面,在 Java 7 中你能够在堆中填满你的字符串。

/**

- Testing String.intern.

*

- Run this class at least with -verbose:gc JVM parameter.

*/

public class InternTest {

public static void main( String[] args ) {

testStringPoolGarbageCollection();

testLongLoop();

}

/**

- Use this method to see where interned strings are stored

- and how many of them can you fit for the given heap size.

*/

private static void testLongLoop()

{

test( 1000 * 1000 * 1000 );

//uncomment the following line to see the hand-written cache performance

//testManual( 1000 * 1000 * 1000 );

}

/**

- Use this method to check that not used interned strings are garbage collected.

*/

private static void testStringPoolGarbageCollection()

{

//first method call - use it as a reference

test( 1000 * 1000 );

//we are going to clean the cache here.

System.gc();

//check the memory consumption and how long does it take to intern strings

//in the second method call.

test( 1000 * 1000 );

}

private static void test( final int cnt )

{

final Listlst = new ArrayList( 100 );

long start = System.currentTimeMillis();

for ( int i = 0; i < cnt; ++i )

{

final String str = "Very long test string, which tells you about something " +

"very-very important, definitely deserving to be interned #" + i;

//uncomment the following line to test dependency from string length

// final String str = Integer.toString( i );

lst.add( str.intern() );

if ( i % 10000 == 0 )

{

System.out.println( i + "; time = " + ( System.currentTimeMillis() - start ) / 1000.0 + " sec" );

start = System.currentTimeMillis();

}

}

System.out.println( "Total length = " + lst.size() );

}

private static final WeakHashMap> s_manualCache =

new WeakHashMap>( 100000 );

private static String manualIntern( final String str )

{

final WeakReferencecached = s_manualCache.get( str );

if ( cached != null )

{

final String value = cached.get();

if ( value != null )

return value;

}

s_manualCache.put( str, new WeakReference( str ) );

return str;

}

private static void testManual( final int cnt )

{

final Listlst = new ArrayList( 100 );

long start = System.currentTimeMillis();

for ( int i = 0; i < cnt; ++i )

{

final String str = "Very long test string, which tells you about something " +

"very-very important, definitely deserving to be interned #" + i;

lst.add( manualIntern( str ) );

if ( i % 10000 == 0 )

{

System.out.println( i + "; manual time = " + ( System.currentTimeMillis() - start ) / 1000.0 + " sec" );

start = System.currentTimeMillis();

}

}

System.out.println( "Total length = " + lst.size() );

}

}

由于 Java 6 中使用固定的内存大小(PermGen)因此不要使用 String.intern() 方法

Java7 和 8 在堆内存中实现字符串池。这以为这字符串池的内存限制等于应用程序的内存限制。

在 Java 7 和 8 中使用 -XX:StringTableSize 来设置字符串池 Map 的大小。它是固定的,因为它使用 HashMap 实现。近似于你应用单独的字符串个数(你希望保留的)并且设置池的大小为最接近的质数并乘以 2 (减少碰撞的可能性)。它是的 String.intern 可以使用相同(固定)的时间并且在每次插入时消耗更小的内存(同样的任务,使用java WeakHashMap将消耗4-5倍的内存)。

在 Java 6 和 7(Java7u40以前) 中 -XX:StringTableSize 参数的值是 1009。Java7u40 以后这个值调整为 60013 (Java 8 中使用相同的值)

如果你不确定字符串池的用量,参考:-XX:+PrintStringTableStatistics JVM 参数,当你的应用挂掉时它告诉你字符串池的使用量信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值