当前位置: 首页 > 面试题库 >

在Java HotSpot vm中将String Literal加载到StringTable的时间

终子昂
2023-03-14
问题内容

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

我找到了一篇中文文章。
Java中新String(“字面量”)中“字面量”是何时进入字符串恒定池的?

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

我发现了一些相对的说法。

jvms第5.4章。链接说

例如,Java虚拟机实现可以选择在使用某个类或接口时分别解析每个符号引用(“惰性”或“最新”分辨率),或者在验证类时一次全部解决(
“急切”或“静态”分辨率)。

我找到了一些有关的openjdk代码 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)的代码

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中的延迟解析。

有人可以明确地说明它。

仅供参考,我不太了解C,但不了解C ++。

谢谢。!


问题答案:

在一个极端的情况下,允许在Java应用程序内检查字符串,然后再进行测试,但是每个字符串只能执行一次。与相同内容的字符串文字一起,可以检测到延迟加载:

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()它并比较引用。有三种可能的方案:

  1. 如果池中存在相同内容的字符串,则将返回该字符串,该字符串必须是与不在池中的字符串不同的对象。

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

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

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

在我的机器上,它会打印:

"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

同样在伊迪欧尼

显示尽管在稍后的代码中有字符串文字,但首次"hello"输入该test方法时该参数不存在"hello"。因此,这证明了字符串文字是延迟解析的。由于我们已经hello手动添加了字符串,因此具有相同内容的字符串文字将解析为相同的实例。

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

如果我们调换测试顺序test('m', 'a', 'i', 'n'); test('h', 'e', 'l', 'l', 'o');"hello"字符串字面量将在第一可用于test调用和保留在池中,所以当我们在第二次调用测试该字符串将已经存在。



 类似资料:
  • 我正在尝试在Java服务器端应用程序中使用ehcache来缓存一些数据。如何在服务器启动时将一些初始数据加载到ehcache。应用程序是具有Spring和数据库连接的基于Web的应用程序。任何人都可以让我知道如何定期刷新这些缓存。 谢啦

  • 问题内容: 如果不使用iframe,则可以加载以下内容: 与外部站点,例如somesitehere.com 页面何时加载?-我知道如何从文件加载内容,但是不确定如何加载整个网站吗? 非常感谢, 问题答案: 无需专门的操作就可以做到。由于标题中提到了jQuery,因此使用了jQuery。

  • 问题内容: 我有一个页面,一个页面包含一个AJAX组件,当用户单击一个按钮时,其内容会更改。我如何知道内容何时加载到? 问题答案: 您需要做两件事: 在您的JavaScript代码中,发出带有自定义URL的AJAX请求已完成的信号: 在您的本机代码中,您需要实现一个侦听此自定义URL 的委托: 不能保证此代码可以解析/编译,但应为您提供实现方法的思路。

  • JEditorPane类型中的read(InputStream,Document)方法不适用于参数(FileInputStream,Document,int)

  • 问题内容: 我有一个PHP include,它需要一段时间才能加载,因为PHP必须获取很多数据。我不想放慢整个网页的加载,以等待包含此内容,那么如何使用ajax加载该包含内容呢?我不希望通过单击按钮来触发Ajax,而只是希望它在页面加载时加载包含,因此,如果您查看下面的示例,则会在显示内含代码的同时显示“更多HTML内容”。 php仍在加载中。 问题答案: 如果您使用的是jQuery,则可以使用他