??xml version="1.0" encoding="utf-8" standalone="yes"?> 转帖地址Q?a >http://congmo.github.com/blog/2012/02/16/1-translationofstring/(葱末) 规范化字W串有如下两个原因: 比如,文件中用逗号分隔?0000人的党籍dHashMapQ那么内存中需?0000左右个字W串用来记录q些党籍。如果将字符串进行规范化Q那么几十个p矣?/p>
使用String.substring()ӞJVM只在栈中分配一个Stringcd的引用,指向原始字符串的字面倹{substring不需要额外分配空_也不需要拷贝字W。String.substring不会对结果进行规范化?/p>
注意Q只要还?#8221;zd”的子串指向原始字W串Q那么垃圑֛收期没法回收它?/p>
String.subString产生的空串也不用自动规范化,因此Q空串也会导致长长的原始字符串没法被回收?/p>
惌避免IZ致原始字符串不能被回收Q就不要使用Mvoid字符串指向原始字W串。void字符串有3中:””,” “,null?/p>
所有字W串在编译期间被规范化,那么E序q行时生的字符串就不能被规范化。这h较恶心的一Ҏ在大多数情况下程序可以正常运行,但是在特D的情况下就会出错。就比如Q?=替代equals来比较两个字W串是否相等Q绝大多数是可行的,因ؓ字符串会被规范化Q但是不排除特例Q比如运行期间生的字符丌Ӏ?/p>
新手喜欢用String s = new String( “hello” );代替String s = “hello”; q与规范化正好相反,q样创徏了一个全新的”hello”字符Ԍ虽然有相同的字面|但是不会被规范化。在两种场景下适合使用new来创建字W串Q?/p> 使用new String( String )׃定会创徏一个全新的字符串吗Q答案是肯定的。你可能以ؓJVM很智能,会将新创建的字符串规范化Q然后返回指向母串的引用。但是语a规范中指出,new String()一定会创徏一个全新的字符Ԍ管JVM在理Z可以同String.substring(0)和String.intern.substring(0)一栯行规范化Q防止出现多个拷贝?/p>
q就引申出另外一个问题,s == s.substring(0)Lq回false吗?{案也是肯定的?/p>
q有一个适合用new来创建字W串的地方,如下Q?/p>
getPassWordҎq回一个字W数l?char)Q这么做q不愚蠢Q在高安全性的场景下,可以将char数组清空?/p>
看下q段代码QString s = new String( “Hello” ); 当变量s所在的c被加蝲的时候,字面?#8221;Hello”会被规范化,但是愚蠢的用new StringQ会在堆中重新创Z份字面?#8221;Hello”Q地址与规范化后的”Hello”不同。在Sun的JVM中,规范化的字符串被存储在一个叫perm gen的特DRAM区域Q这个区域中JVM也加载类和存储本地编译后的代码,而且规范化后的字W串与存储在堆中的普通对象一栗如果这样写QString s = “Hello”Q就不会重新创徏”Hello”的副本,而是直接指向规范化后的字W串?/p>
在JDK的早L本中Q由于JVM要持有存储规范化后字W串的HashTable的引用,以便查新创徏的字W串是否已在׃n池中存在Q这样就D了规范化后的字符串没法被垃圾回收器回收。随着1.2版本中引入了弱引用之后,无用的规范化字符串就可以被回收了?/p>
JDK1.2版本之后Q规范化字符串在没用引用指向它时Q可以被回收Q而且规范化不是只发生在编译期。这样以~码的方式重新创建、规范化字符串时Q新创徏的字W串对象会变成唯一的原始字W串。这样做不会带来实际的问题,使用==来比较两个字W串包含的字W是否相{同样奏效?q里理解的不是很好,我觉得应该是q样的:同一个字面D范化后,之前的那个字面值的地址会被新地址替换? java.lang.OutOfMemoryError: String intern table overflow 表示规范化字W串太多。一些低版本的JVM规定规范化字W串不能过64K(大约50000?。IBM的Java1.1.8 JRE有q样的限制。它是ErrorQ不是ExceptionQ如果想捕获它,可以q样做: 依旧要注意规范化?#8221;不利”垃圾回收?/p>
q里只讲底层规范化如何v作用的最单Ş式。JVM内部在堆中存储对象,包括规范化与普通的String对象(q个说法貌似不是很严?。而且规范化的String被放在一?#8221;?#8221;HashMap中?/p>
HashMap中的String集合Q也叫字W串帔R池。他们和堆中其他普通对象没什么两P只是因ؓl过优化后,生存期要长一些。String对象在堆中,而指向它的引用存在HashMap中,所以规范化字符串有自己的共享池?/p>
当字W串被规范化Ӟ先在HashMap中检查是否已存在Q如果存在则q回指向dW串的引用,通常q个引用优先自n的引用,而自w的副本很快被垃圾回收器回收。如果没有,则将其引用添加到HashMap中,q注册ؓdW串。规范化的过E不会再生成字符串的副本Q只是持有主字符串的唯一引用?/p>
规范化与非规范化的字W串都存储在堆中。由于规范化时生的是弱引用Q所以当除了HashMap中的弱引用再无其他引用指向主字符串时Q该dW串可以被回收了?/p>
new StringӞ不会自动规范化,因此在堆中会有同一个字W串的多个副本。随后调用该字符串的internҎQ这些副本也不会被清除?/p>
我L觉这里貌似有问题Q干脆不译了,把原文脓上吧?/p>
规范化最大的问题是知道E序l束才能销毁占用RAM的空_管再没有引用指向主字符Ԍ也不能被垃圾回收器回?早期版本)。如果想使用一个时的规范化字W串Q可以用手动规范化?/p>
然而,现在L的JVM中的规范化字W串׃n池都是采用弱引用实现的,所以只要没有强引用指向dW串Q则可被垃圾回收器回收。你可以像JVM一P自己实现规范化的q程?/p>
比如假设从文件中d以逗号分隔的h名与地址Qƈ以某U顺序存入集合,׃很多人居住在同一城市Q所以RAM中就会充满了同一个城市的副本?/p>
那么创徏一个HashMap(不是HashSet),用于存储每个城市名称的主字符丌Ӏ每ơ获取城市时Q先从HashMap中查找,如果存在则用dW串的引用替换自w的引用。自wString对象的副本很快就会被垃圾回收器回收。如果不存在增加城市到HashMap?/p>
当读完城市后Q就可以讲HashMap抛弃Q而放入到HashMap中的dW串Q除了没有其他引用指向的dW串被垃圑֛收器回收掉之外,q是一样存在,一h有唯一的引用,而且与规范化后的字符串一栗?/p>
原文地址Q?a >http://mindprod.com/jgloss/interned.html q里q译完了Q不q有些地方觉得怪怪的。还有由于个人水q_在是有限Q难免有地方_糙。另外,如果你说研究q个实在是没有意思类似的话,那拜托你憋在心里吧,谢谢了?/p>
因ؓ在看jdk源码Q看到String中最后一行的intern是个nativeҎQ于是就到处查资料,q在OSChina上提Z个问题:http://www.oschina.net/question/129471_38493Q讨Z提C撒加在javaeye上的一个帖子的回答Q?a >http://www.iteye.com/topic/1112592Q于是我做了如下的测试,又画?张图?/p>
试环境Q?
从前面两D代码中可以看出Q用命令行的方式同栯入参?#8221;congmo.github.com”Q将args0赋值给str0Q然后str0.intern()==str0的结果竟然是falseQ难道真如javaeye那篇帖子中有人怀疑的那样QJVMargs0提前p范化了?按道理应该不会啊?/p>
试环境Q?
但是?.7版本执行的结果看来,貌似可以定JVM没有对args0规范化,但是从javaeye帖子讨论中可以知?.7版本后perm genq个内存q掉了,所以规范化之后的字W串也存储在堆中Q所以无论args0有没有提前被规范化,str0始终都会指向堆中那个引用。按照我的理解,如下图所C: 所以现在看来还是个未知数?/p>
另外Q我按照自己的理解针?中情는?张图Q都是用于说明JVM的内存分配的?注:jdk1.6或之前版本,1.7之后Ҏ砍掉?/p>
q两张图都是描述使用new创徏StringQ然后再调用自n的internҎ后内存以及引用的变化?/p> 译者注Q翻译这文章是有目的性的Q不是闲来无事打发时间。刚刚看完String的源码,虽然看完Q但是有很多东西(或者说”陷阱”)在源码中得不C现。可能是在编译器中进行了优化。无意中发现了这文章,里面讲述了一些隐含的Q源码中比较隐晦或者看不到的东ѝ比如substring,intern{。所以才有了译?#8221;动机”Q还有一专门讲qintern的,在之二中翻译。另Q翻译纯属个为,因技术与p水准有限Q文中肯定不乏欠妥之处,如果你能文明的指出,在下感Ȁ不尽。如a辞中满是不尊重,则请收回。希望能带给其大家帮助,以达共同q步之目的?/p>
Java中的字符串不同于与C++中的字符Ԍ不能改动字符串中的字W。预查找字符串中某个字符Q可是用charAt()Ҏ。Java中的字符串都?6位的Unicode。可是用StringBuffer或者char修改字符丌Ӏ从1.5版本之后Q可以用StringBuilder替代StringBufferQStringBuilder速度更快Q但是是U程不安全的?/p>
String.length()用来获取字符串的长度Q而不是像其他cM使用的length或size()?/p>
Java中有3U空字符Ԍnull,”“?#8221; “。下面就是如何区别这3中空字符串的Ҏ?/p>
?/p>
当s为nullӞ不会抛出异常Q只会当作它们不相等?除非使用String.intern()对字W串q行合ƈ(interned)Q否则不可以使用==来判断两个字W串是否相等。要使用equals()Ҏ来比较?/p>
如果一不小心误?=来比较字W串Q编译器也不会发告。不q的是,q个bug直到~译器或者虚拟机昑ּq行规范?interning)Ӟ才会凸显出。规范化(interning)之后Q会获得一个字W串的原始引用。这样其他字W串的副本就可以很快被垃圑֛收器回收。然而,规范?interning)?点不I 如果x较两个字W串的大,׃能用常规的比较操作了,可以使用compareTo()或compareToIgnoreCase()Ҏ替代?/p>
compareTo的返回| q个时候可以粗略的把字W串当作数字。返回值就是s-t?/p>
新手可能会因Z面的几个l果感到惊奇Q?/p> 当实现自qcLQ默认的Object.equals不会一个个字段q行比较。需要自行实现equals来比较。默认equals只是比较两个引用是否指向同一个对象?/p>
字符串搜索可使用indexOf和lastIndexOf。他们都可以通过fromOffset改变搜烦开始的位置。返回的l果是相对于字符串开始的位置(0)Q而不是相对于fromOffset的位|。如果搜索时忽略大小写,可先字W串全部转换成大写或写。可以这样实玎ͼ 查找单个字符有很多方法,其中不乏速度比一个一个字W比较是否相{快。理x况下Q编译器_的将indexOfҎ单个字符参数转化为charQ那么可以将x.indexOf(y) >= 0 化ؓx.contains(y)?/p>
字符串是不可变的Q因此字W串不仅可以被无限期重用Q而且q可在很多场景下׃n。当你将一个字W串变量赋给另外一个字W串变量Ӟ不会再次产生副本。甚臛_调用substring后,赋给了新的变量,也不会创建新的字W串。只有在一下几U情况下才会创徏新的字符Ԍ 每种对象都可以调用toStringҎ自w的内容转化成hcdȝ形式。通常Q编写自定义cLQ尽仅仅是ZdegubQ也要单独实现toStringҎ?/p>
q样来调用:String toShow = myThing.toString(); 默认的Object.toString()很不Q它不会像你期待的那P类中所有字DD出。要辑ֈq种预期Q就要自q码实现。默认的toStringҎ会比较对象的hashCode或者对象的地址?/p>
toStringҎ有个奇的地斏V在需要{换ؓ字符串时Q好像自动调用toStringq行了{换?/p> String.replace( char target, char replacement )、String. replace( String target, String replacement ) 两个Ҏ都是替换目标字符串中出现的所有指定的字符或字W串Q但是前者要比后者快很多。所以在替换单个字符Ӟ要用前者,即用单引号。不q的是,后者只有在1.5及其之后的版本中才可以用?/p>
replaceAll( String regex, String replacement ) Ҏ也是全部替换Q区别在于replaceAllҎ使用正则表达式搜索。欲使用replace( String target, String replacement ) 时千万不能用replaceAll(String regex, String replacement) 。第二个参数不是单的字符ԌString. replaceAll 与Matcher. replaceAll 一栗?代表匚w字符串的引用Q\则是正则表达式中的关键字Q所以需要将\转义为\\\\Q将$转义为\\$?/p>
replaceFirst( String regex, String replacement ) 也用正则表辑ּ?/p>
Javadoc中String.replace是以 CharSequence为入参的Q别担心QString实现?CharSequence接口Q所以replace可以在String或StringBuilder中正怋用?/p>
String中包含很多非常好用的正则表达式方法,比如split、matches、replaceAllq有replaceFirst。通常情况下推荐用高效的java.util.regex中的ҎQ方法中的Pattern被提前编译,q且可重用。在不考虑效率的情况下Q就可以使用String中的正则表达式方法了?/p>
replaceAll和replace都以低效的方式实玎ͼ每次调用都要重新~译regex pattern?/p>
所以,如果不止一ơ调用replace或replaceAllӞ最好用单独的正则表达式,~译一ơ即可重用?/p>
substring很智能,与其他编E语a的深拯不同Q它只是创徏一个指向原始不可变字符串的引用。比如根据substring参数讄char的偏Ud|与count属性值后Q返回一个指向它的引用,而不是全部拷贝。这样就l调试增M困惑Q因为每ơ看到的都是整个字符串而不是截取后的子丌Ӏ这样做有一个致命的~点Q就是子串一直保持着整个原始字符串的引用Q这样即使原始字W串已经没用了,也不能被垃圾回收器回收?事实上String对象的引用可以被回收Q但是RAM中的char没法被回? 所以查扑֭W串Ӟ使用indexOf(lookFor, offset)要好于先使用substring创徏子串再用indexOf(lookFor)?/p>
如果切的知晓小子串会指向RAM中原始大字符串的charQ其不能被回收Q这个时候可以用littleString = new String(littleString)来创Z个与原始字符串无关的新字W串来避免这U情늚发生?/p>
如果你是通过src.zip来学习String.substring()Q那么这U?#8221;陷阱”很难被发现。因为它是用qString的一个非公有构造方法String (int offset, int count, char value) 来调整value的偏Ud和count值来实现?/p>
原文链接Q?a >http://mindprod.com/jgloss/string.html
]]>
规范化的字符串可节省I间Q代价就是花Ҏ多的CPU旉来检存储在RAM中的字符串和替换字符串副本。规范化之后的字W串Q不论存在多引用,仅在RAM中存在一份。由于String是不可变的,所以比如两个不同的Ҏy使用同一个字W串Q那么它们就可以使用同一个String的副本。不论字W串的意思在不同的语境下是否相同Q依旧可以共享,好比sin可以是h名,当然也是三角函数中的函数名。共享重复字W串的过E就叫做规范化。String.intern()q回规范化的dW串的引用。规范化之后的字W串可以直接使用==(比较引用)来比较两个字W串是否相等。由于String不可变的Ҏ,可以节省很多I间。比?#8221;pot”?#8221;hippopotamus”中出玎ͼ那么׃需要创建新的字W串Q额外分配新的空?堆中的空?Q返回一个相应指?#8221;hippopotamus”的引用即可?/p>
Z要规范化
规范化与String.substring()
1 public static void main(String args[]){
2 String s = "a very long string";
3 // create an empty substring
4 String e1 = s.substring( 0,0);
5 // make sure the empty string is canonical
6 String e2 = ( e1.length() ==0) ? "" :e1;
7 System.out.println( e1=="" );// always prints false
8 System.out.println( e2=="" );// always prints true
9 }
规范化与void字符?/h3>
1 public final static String possiblyEmpty( StringpString)
2 {
3 if( pString==null) return"";
4 pString=pString.trim();
5 if( pString.length() ==0) return"";
6 returnpString;
7 }
8 public final staticStringpossiblyNull( StringpString)
9 {
10 if( pString==null) returnnull;
11 pString=pString.trim();
12 if( pString.length() ==0) returnnull;
13 returnpString;
14 }
15 public final staticStringneverNull( StringpString)
16 {
17 /* if pString is null, Java will throw an NullPointerException */
18 pString=pString.trim();
19 /* if pString is empty or blank, throw a NullPointerException */
20 if( pString.length() ==0) throw newNullPointerException();
21 returnpString;
22 }
规范化疑难杂?/h3>
规范化与new String( String )
1 String password = new String( jpassword.getPassWord() );
规范化与垃圾回收
溢出
1 public class InternTest
2 {
3 public static final intn=80000;
4 public static void main( String[] args)
5 {
6 String[] hold = new String[n];
7 // build list of interned strings
8 for( inti=0;i<n;i++)
9 {
10 try
11 {
12 hold[i] =Integer.toString(i).intern();
13 }
14 catch( Throwablee)
15 {
16 System.out.println( "intern exploded at " +i);
17 System.exit( 1);
18 }
19 }
20 // make sure they were really interned.
21 for( inti=0;i<n;i++)
22 {
23 if( hold[i] !=Integer.toString(i).intern() )
24 {
25 System.out.println( "intern failed at " +i);
26 System.exit( 1);
27 }
28 }
29 System.out.println( "intern good for at least " +n+" Strings." );
30 }
底层
This is a simplified version of how interning works under the hood. Inside the JVM is the heap where all allocated Objects reside. This includes Strings both interned and ordinary. (In Sun’s JVM, the interned Strings (which includes String literals) are stored in a special pool of RAM called the perm gen, where the JVM also loads classes and stores natively compiled code. However, the intered Strings behave no differently than had they been stored in the ordinary object heap.) In addition, interned Strings are registered in a weak HashMap.The collection of Strings registered in this HashMap is sometimes called the String pool. However, they are ordinary Objects and live on the heap just like any other (perhaps in an optimised way since interned Strings tend to be long lived). The String Object lives on the heap and a reference to it lives in the HashMap. There is so separate pool of interned String objects. Whenever a String is interned, it is looked up in the HashMap to see if it exists already. If so the user gets passed a reference to the master copy. Normally he will use that copy in preference to his. His duplicate copy then will likely soon have no references to it and will be eventually garbage collected. If the String has never been seen before, a reference to it will be added to the HashMap and intern will hand him a reference to his own String, now registered as the unique master. Note that the intern process does not make a copy of the String, it just keeps a reference to the unique master copies. All the Strings, interned and ordinary live on the heap. When there are no references left to a String except the intern HashMap registry reference, it will be garbage collected since intern keeps only a weak reference to it. When you say new String, it is not automatically interned. Thus there may then be duplicates on the heap. If you later use intern on that String, those duplicates won’t be cleaned up. Only when you intern all copies of a String, and discard references to the uninterned versions do you maintain but a single copy.
手动规范?/h3>
java version "1.6.0_17" Java(TM) SE Runtime Environment (build 1.6.0_17-b04) Java HotSpot(TM) Client VM (build 14.3-b01, mixed mode, sharing)
1 public static void main(String[] args) {
2 String str0 = "congmo.github.com";
3 System.out.println(str0.intern() == str0);
4 }
输出l果Qtrue
1 public static void main(String[] args) {
2 String str0 = args[0];
3 System.out.println(str0.intern() == str0);
4 }
同样在命令行输入:congmo.github.com
输出l果Q?br />false 1 public static void main(String[] args) {
2
3 String str0 = "congmo.github.com";
4 System.out.println(str0.intern() == str0);
5
6 String str1 = new String( args[0] );
7 System.out.println(str1.intern() == str1);
8
9 System.out.println(str0 == str1.intern());
10 }
输出l果Q?br />true
false
truejava version "1.7.0_02" Java(TM) SE Runtime Environment (build 1.7.0_02-b13) Java HotSpot(TM) Client VM (build 22.0-b10, mixed mode, sharing)
1 public static void main(String[] args) {
2 String str0 = args[0];
3 System.out.println(str0.intern() == str0);
4 }
输出l果Q?true
1 public static void main(String[] args) {
2 String str0 = new String( args[0] );
3 System.out.println(str0.intern() == str0);
4 }
输出l果Q?true
1 public static void main(String[] args) {
2 String str0 = args[0];
3 System.out.println(str0.intern() == str0);
4 String str = new String( args[0] );
5 System.out.println(str.intern() == str);
6 System.out.println(str.intern() == str0);
7 }
输出l果Q?br />true
false
true
]]>
I字W串
1 if( s==null) echo( "was null" );
2 else if( s.length() ==0) echo( "was empty" );
3 else if( s.trim().length() ==0) echo( "was blank or other whitespace" );
字符串比?/h3>
1 if( "abc".equals(s) ) echo( "matched" );
1 if( s.equals( "abc" ) ) echo( "matched" );
1 String s ="apple";
2 String t ="orange";
3 if( s.compareTo(t) <0)
4 {
5 System.out.println( "s < t" );
6 }
大小写敏感与大小写不敏感比较
1 // String comparison, case-sensitive and insensitive.
2 Stringapple="apple";
3 Stringorange="orange";
4
5 // case-sensitive compare for equality, faster than order comparison.
6 booleansame=apple.equals( orange);
7
8 // case-insensitive compare for equality, slower that case-sensitive comparison.
9 booleansame=apple.equalsIgnoreCase( orange);
10
11 // case-sensitive compare for order.
12 // +ve if apple>orange, 0 if apple==orange, -ve if apple<orange
13 intorder=apple.compareTo( orange);
14
15 // case-insensitive compare for order.
16 // +ve if apple>orange, 0 if apple==orange, -ve if apple<orange
17 intorder=apple.compareToIgnoreCase( orange);
18
19 // If you are going compare the same strings over and over,
20 // and you want to compare them in a case-insensitive way, it may pay
21 // to convert them to lower case, and use the faster case-sensive compare.
22 StringlcApple=apple.toLowerCase();
23 StringlcOrange=orange.toLowerCase();
24
25 // effectively a case-insensitive compare for equality,
26 booleansame=lcApple.equals( lcOrange);
27
28 // effectively a case-insensitive compare for order.
29 // +ve if apple>orange, 0 if apple==orange, -ve if apple<orange
30 intorder=lcApple.compareTo( lcOrange);
字符串搜?/h3>
1 public static voidmain( String[] args)
2 {
3 // use of indexOf
4 finalStrings1="ABCDEFGABCDEFG";
5 out.println( s1.indexOf( "CD" ) );
6 // prints 2, 0-based offset of first CD where found.
7
8 out.println( s1.indexOf( "cd" ) );
9 // prints -1, means not found, search is case sensitive
10
11 out.println( s1.toLowerCase().indexOf( "cd" ) );
12 // prints 2, 0-based offset of first cd where found
13
14 out.println( s1.indexOf( "cd".toUpperCase() ) );
15 // prints 2, 0-based offset of first cd where found
16
17 out.println( s1.indexOf( "CD",4/* start looking here, after the first CD */) );
18 // prints 9, 0-based offset relative to the original string,
19 // not relative to the start of the substring
20
21 // use of last indexOf
22
23 out.println( s1.lastIndexOf( "CD" ) );
24 // prints 9, 0-based offset of where last CD found.
25
26 out.println( s1.lastIndexOf( "cd" ) );
27 // prints -1, means not found, search is case sensitive
28
29 out.println( s1.toLowerCase().lastIndexOf( "cd" ) );
30 // prints 9, 0-based offset of where last cd found
31
32 out.println( s1.lastIndexOf( "cd".toUpperCase() ) );
33 // prints 9, 0-based offset of where last cd found
34
35 out.println( s1.lastIndexOf( "CD",8/* start looking here, prior to last */) );
36 // prints 2, 0-based offset relative to the original string,
37 // not relative to the start of the substring
38
39 out.println( "\u00df" );
40 // prints German esset ligature sz single ss bate-like glyph
41
42 out.println( "\u00df".toUpperCase() );
43 // prints SS, not SZ, two chars long!
44 }
45 }
创徏字符?/h3>
toStringҎ
字符串替?/h3>
正则表达?/h3>
1 // how replace is implemented.
2 // It uses regex techniques even though neither parameter is a regex.
3 publicStringreplace(CharSequencetarget,CharSequencereplacement)
4 {
5 returnPattern.compile( target.toString(),Pattern.LITERAL)
6 .matcher( this).replaceAll( Matcher.quoteReplacement( replacement.toString() ) );
7 }
substring
http://mindprod.com/jgloss/substring.html
]]>
S0:Survior1区内存占?br />S1:Survior2区内存占?br />E:Eden(新生?Eden)
O:Old(老年?
P:持久?br />YGC:新生代gcơ数(minor gc)
YGCTQgc旉
FGCQfull gc ơ数
FGCT:full gc旉
GCT: 总gc旉
3.gc日志输出
-XX:+PrintGC gc概要信息
-XX:+PrintGCDetails gc详细信息
-XX:+PrintGCTimeStamps GC停顿耗时
-XX:+PrintGCApplicationStopedTime 用户q程停顿旉(stop the world)
再加?Xloggc:文g路径 gc信息会输出到指定的文g?br />4.jconsole可以q程或者本地监控jvm内存信息Q线E信? cd载信?MBean信息
5.jmap
6.jhat
7.jvisualVm
8.eclipse memory analysis
]]>package cn.com.pbqi.corejava;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
public class CardGame {
private int pNum;
private List<String> cardList = new ArrayList<String>(54);
private Map<String,List<String>> map = new TreeMap<String,List<String>>();
/**
* 打牌的h?最?个h,最?个h
* @param pNum
*/
public CardGame(int pNum) {
if(pNum < 2 || pNum > 4) {
throw new IllegalArgumentException("CardPlayer must between 2 and 4, CardPlayer=" + pNum);
}
this.pNum = pNum;
for(int i = 0; i <pNum; i++) {
map.put(i+"-", new ArrayList<String>());
}
this.initCards();
this.distribute();
this.display();
}
/**
* 初始化一副扑?br />
*/
public List<String> initCards() {
String[] type = {"r","b","s","m"};
String[] cards = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
String[] kings = {"大王","王"};
for(int i = 0; i < type.length; i++) {
for(int j = 0; j < cards.length;j++) {
cardList.add(cards[j]+type[i]);
}
}
for(int k = 0; k < kings.length; k++){
cardList.add(kings[k]);
}
return cardList;
}
/**
* 发牌
*/
public void distribute() {
Random r = new Random();
int len = cardList.size();
int bakLen = len;
for(int i = 0; i < len; i++) {
int rNum = r.nextInt(bakLen);
String card = cardList.get(rNum);
int left = i % pNum;
map.get(left+"-").add(card);
cardList.remove(rNum);
bakLen--;
}
}
public void display() {
System.out.println("======r:U桃,b:黑桃,s:方块,m:c===========");
for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext();) {
String key = iter.next();
List<String> list = map.get(key);
System.out.print(key+ " 的牌?==");
for(int i = 0; i < list.size();i++) {
System.out.print(list.get(i));
if(i != list.size() -1) {
System.out.print(",");
}
}
System.out.println("");
}
}
public static void main(String[] args) {
CardGame cg = new CardGame(4);
}
}
]]>
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class TestRandom {
public final static int TOTAL = 33;
public final static int NUMBER = 7;
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
StringBuffer sb = new StringBuffer();
Random r = new Random();
for(int i = 0; i < TOTAL; i++) {
list.add(i + 1 + "");
}
for(int j = 0; j < NUMBER; j++) {
int size = list.size();
String s = list.get(r.nextInt(size));
sb.append(s);
if(j != NUMBER -1) {
sb.append(",");
}
list.remove(s);
}
System.out.println(sb.toString());
}
}