String Literal在Java HotSpot vm中加载到StringTable的时间 [英] the timing of String Literal loaded into StringTable in Java HotSpot vm

查看:150
本文介绍了String Literal在Java HotSpot vm中加载到StringTable的时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我学习java.lang.String Java API时,问题就出来了。

The Question came out when i was learning java.lang.String Java API.

我发现了一篇中文文章。
Java中新字符串(字面量)中字面量是何时进入字符串常量池的?

I found an article in Chinese. Java 中new String("字面量") 中 "字面量" 是何时进入字符串常量池的?

它说, CONSTANT_String 是HotSpot中的延迟解析VM,所以String Literal被加载到StringTable util中使用它。

it said,CONSTANT_String is lazy resolve in HotSpot VM, so String Literal is loaded into StringTable util it is used.

我找到了一些相关的说法。

And i found some relavant saying.

jvms Chapter 5.4。链接


例如,Java虚拟机实现可以选择单独解析类或接口中的每个符号引用使用它(懒惰或迟分辨率),或者在验证类时(急切或静态分辨率)立即解决所有问题。

For example, a Java Virtual Machine implementation may choose to resolve each symbolic reference in a class or interface individually when it is used ("lazy" or "late" resolution), or to resolve them all at once when the class is being verified ("eager" or "static" resolution).

我发现了一些关于 ldc

IRT_ENTRY(void, InterpreterRuntime::ldc(JavaThread* thread, bool wide))  
  // access constant pool  
  constantPoolOop pool = method(thread)->constants();  
  int index = wide ? get_index_u2(thread, Bytecodes::_ldc_w) :get_index_u1(thread, Bytecodes::_ldc);  
  constantTag tag = pool->tag_at(index);  

  if (tag.is_unresolved_klass() || tag.is_klass()) {  
    klassOop klass = pool->klass_at(index, CHECK);  
    oop java_class = klass->java_mirror();  
    thread->set_vm_result(java_class);  
  } else {  
#ifdef ASSERT  
    // If we entered this runtime routine, we believed the tag contained  
    // an unresolved string, an unresolved class or a resolved class.  
    // However, another thread could have resolved the unresolved string  
    // or class by the time we go there.  
    assert(tag.is_unresolved_string()|| tag.is_string(), "expected string");  
#endif  
    oop s_oop = pool->string_at(index, CHECK);  
    thread->set_vm_result(s_oop);  
  }  
IRT_END  

和关于pool-> string_at的代码(index,CHECK )

and code about pool->string_at(index, CHECK)

oop constantPoolOopDesc::string_at_impl(constantPoolHandle this_oop, int which, TRAPS) {  
  oop str = NULL;  
  CPSlot entry = this_oop->slot_at(which);  
  if (entry.is_metadata()) {  
    ObjectLocker ol(this_oop, THREAD);  
    if (this_oop->tag_at(which).is_unresolved_string()) {  
      // Intern string  
      Symbol* sym = this_oop->unresolved_string_at(which);  
      str = StringTable::intern(sym, CHECK_(constantPoolOop(NULL)));  
      this_oop->string_at_put(which, str);  
   } else {  
      // Another thread beat us and interned string, read string from constant pool  
     str = this_oop->resolved_string_at(which);  
    }  
  } else {  
    str = entry.get_oop();  
  }  
  assert(java_lang_String::is_instance(str), "must be string");  
  return str;  
}  

但是

这些代码只能证明String Literal可能加载到StringTable util ldc 中,但无法在HotSpot VM中证明延迟解析。

those code only could prove String Literal maybe loaded into StringTable util ldc, but can not prove lazy resolve in HotSpot VM.

有人可以明确地解释它。

Could someone explicate it explicitly.

仅供参考,我知道很少c而不是c ++。

FYI, i know little c but not c++.

谢谢。 !

推荐答案

有一个角落案例允许在Java应用程序中检查测试之前池中是否存在字符串,但每串只能做一次。与相同内容的字符串文字一起,可以检测到延迟加载:

There is a corner case which allows to check within a Java application whether a string existed in the pool prior to the test, but it can be done only once per string. Together with string literals of the same content, the lazy loading can be detected:

public class Test {
    public static void main(String[] args) {
        test('h', 'e', 'l', 'l', 'o');
        test('m', 'a', 'i', 'n');
    }
    static void test(char... arg) {
        String s1 = new String(arg), s2 = s1.intern();
        System.out.println('"'+s1+'"'
            +(s1!=s2? " existed": " did not exist")+" in the pool before");
        System.out.println("is the same as \"hello\": "+(s2=="hello"));
        System.out.println("is the same as \"main\": "+(s2=="main"));
        System.out.println();
    }
}

测试首先创建一个新的字符串实例存在于池中。然后它在其上调用 intern()并比较引用。有三种可能的情况:

The test first creates a new string instance which does not exist in the pool. Then it calls intern() on it and compares the references. There are three possible scenarios:


  1. 如果池中存在相同内容的字符串,则返回该字符串是不同于我们的字符串不在池中的对象。

  1. If a string of the same contents exists in the pool, that string will be returned which must be a different object than our string not being in the pool.

我们的字符串被添加到池中并返回。在这种情况下,两个引用是相同的。

Our string is added to the pool and returned. In this case, the two references are identical.

将创建具有相同内容的新字符串并将其添加到池中。然后,返回的引用将是不同的。

A new string with the same contents will be created and added to the pool. Then, the returned reference will be different.

我们无法区分1和3,所以如果是JVM通常在 intern()中向池添加新字符串,我们运气不好。但是如果它添加了我们正在调用 intern()的实例,我们可以识别方案2并确定该字符串不在池中,但已经添加为我们测试的副作用。

We can’t distinguish between 1 and 3, so if a JVM generally adds new strings to the pool in intern(), we are out of luck. But if it adds the instance we’re calling intern() on, we can identify scenario 2 and know for sure that the string wasn’t in the pool, but has been added as a side effect of our test.

在我的机器上,它打印:

On my machine, it prints:

"hello" did not exist before
is the same as "hello": true
is the same as "main": false

"main" existed before
is the same as "hello": false
is the same as "main": true

同样在 Ideone

显示输入测试hello不存在尽管后面的代码中有一个字符串文字hello,但第一次使用c>方法。所以这证明了字符串文字被懒惰地解决了。由于我们已经手动添加了 hello 字符串,因此具有相同内容的字符串文字将解析为同一个实例。

showing that "hello" did not exist when entering the test method the first time, despite there is a string literal "hello" in the code later-on. So this proves that the string literal is resolved lazily. Since we already added a hello string manually, the string literal with the same contents will resolve to the same instance.

相比之下,池中已经存在main字符串,这很容易解释。 Java启动程序搜索要执行的 main 方法,因此,将该字符串作为副作用添加到池中。

In contrast, the "main" string already exists in the pool, which is easy to explain. The Java launcher searches for the main method to execute, hence, adds that string to the pool as a side effect.

如果我们将测试的顺序交换为 test('m','a','i','n'); test('h','e','l','l','o'); hello字符串文字将在第一个 test 调用中使用并保留在池中,因此当我们在第二次调用中测试它时,该字符串将已经存在。

If we swap the order of the tests to test('m', 'a', 'i', 'n'); test('h', 'e', 'l', 'l', 'o'); the "hello" string literal will be used in the first test invocation and remains in the pool, so when we test it in the second invocation the string will already exist.

这篇关于String Literal在Java HotSpot vm中加载到StringTable的时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆