我想在垃圾收集之前打印整个字符串池,其中包含使用String
添加的文字和intern()
对象。
JDK是否存在隐含此类操作的方法?我们如何检查字符串池?
答案 0 :(得分:13)
编辑:评论表明可能存在对这种“黑客”行为的误解。它打印了(直接或间接)调用intern()
的字符串,如问题中所述。它不会打印“整个字符串池”,因为字符串池只驻留在JVM中,填充了在类加载和初始化期间出现的符号和字符串,并且无法从Java端访问。 子> 的
NeplatnyUdaj在评论中提到可能有可能定义一个新的java.lang.String
类并在启动时将其隐藏到JVM中。我很好奇,并试了一下。我应该说什么:它有效!
1。创建包含包java.lang
2. 将这样的类插入此包
package java.lang;
import java.util.LinkedHashSet;
import java.util.Set;
public class StringPool {
private static Set<String> pool = null;
public static synchronized void store(String string)
{
try
{
if (pool == null)
{
pool = new LinkedHashSet<String>();
}
pool.add(string);
}
catch (Exception e)
{
// Ignore
}
}
public static synchronized Set<String> getPool()
{
return new LinkedHashSet<String>(pool);
}
}
3。复制&amp;将原始java.lang.String
类粘贴到此包中。令人惊讶的是,这没有太多问题。它会抱怨一个函数,即调用
h = sun.misc.Hashing.murmur3_32(HASHING_SEED, value, 0, value.length);
可以安全地替换为
h = 0;
4. 更改新String#intern()
课程的String
方法。最初,这是一种native
方法。它可以替换为
public String intern()
{
StringPool.store(this);
return this;
}
5. 从此项目创建一个.JAR文件,并将其存储为例如newString.jar
6。使用生成/包含/使用某些字符串的测试类创建另一个项目。 (这应该很简单)并编译这个类,可以命名为NewStringTest
7. 使用修改后的字符串类启动测试程序:
java -Xbootclasspath:newString.jar;C:\jre\lib\rt.jar NewStringTest
然后可以使用StringPool#getPool()
方法获取包含实习字符串的池。
我刚用下面的类测试了这个,它手动创建了一些字符串,以及一些Swing组件(可以预期包含一些字符串):
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
public class NewStringTest
{
public static void main(String[] args)
{
generateSomeStrings();
System.out.println(StringPool.getPool());
}
private static void generateSomeStrings()
{
String s = "This is some test string";
for (int i=0; i<10; i++)
{
String t = s + i;
t.intern();
}
try
{
SwingUtilities.invokeAndWait(new Runnable()
{
@Override
public void run() {
JFrame frame = new JFrame();
JTable table = new JTable();
}
});
}
catch (InvocationTargetException e)
{
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
输出
[hashSeed,value,buf,J,D,Z,seed,segmentShift,segmentMask, segment,state,head,tail,waitStatus,next,Ljava / lang / String;, 我,[C,[J,Ljava / util / Hashtable;,Ljava / security / PermissionCollection;, Ljava / util / Vector;,Ljava / lang / Class;,main,这是一些测试string0, 这是一些测试string1,这是一些测试string2, 这是一些测试string3,这是一些测试string4, 这是一些测试string5,这是一些测试string6, 这是一些测试string7,这是一些测试string8, 这是一些测试string9,INSTANCE,es ,, ES,sv,SE, values,Ljava / lang / Object;,[Ljava / awt / Component;, Ljava / awt / LayoutManager;,Ljava / awt / LightweightDispatcher;, Ljava / awt / Dimension;,createUI,invoke,VK_F10, VK_CONTEXT_MENU,VK_SPACE,VK_LEFT,VK_KP_LEFT, VK_RIGHT,VK_KP_RIGHT,VK_ESCAPE,VK_C,VK_V,VK_X, VK_COPY,VK_PASTE,VK_CUT,VK_INSERT,VK_DELETE, VK_DOWN,VK_KP_DOWN,VK_UP,VK_KP_UP,VK_HOME,VK_END, VK_PAGE_UP,VK_PAGE_DOWN,VK_TAB,VK_ENTER,VK_A, VK_SLASH,VK_BACK_SLASH,VK_F2,VK_F8]
答案 1 :(得分:-1)
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#finalize%28%29,因此GC在清理任何对象之前调用finalize方法。
所以String中的finalize方法也被调用了。但遗憾的是,String是最后一堂课,你无法覆盖它。 (Why is String class declared final in Java?)
但是如果你真的想要让这个东西工作,那么你需要创建自己的名字别名的字符串对象,但内部行为将保持所有字符串的功能。
对于有保证的GC,请尝试以下方法:http://code.google.com/p/jlibs/wiki/GarbageCollection