4

这是OpenJDK6 的hotspot/src/share/vm/prims/unsafe.cpp代码片段(从第 1082 行开始):

// JSR166 ------------------------------------------------------------------

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
  UnsafeWrapper("Unsafe_CompareAndSwapObject");
  oop x = JNIHandles::resolve(x_h);
  oop e = JNIHandles::resolve(e_h);
  oop p = JNIHandles::resolve(obj);
  HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);
  if (UseCompressedOops) {
    update_barrier_set_pre((narrowOop*)addr, e);
  } else {
    update_barrier_set_pre((oop*)addr, e);
  }
  oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e);
  jboolean success  = (res == e);
  if (success)
    update_barrier_set((void*)addr, x);
  return success;
UNSAFE_END

还添加了关键方法oopDesc::atomic_compare_exchange_oop

 inline oop oopDesc::atomic_compare_exchange_oop(oop exchange_value,
                                                    volatile HeapWord *dest,
                                                    oop compare_value) {
      if (UseCompressedOops) {
        // encode exchange and compare value from oop to T
        narrowOop val = encode_heap_oop(exchange_value);
        narrowOop cmp = encode_heap_oop(compare_value);

        narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp);
        // decode old from T to oop
        return decode_heap_oop(old);
      } else {
        return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value);
      }
    }

这段代码在 JVM 上下文中的目的是什么?我在 C++ 方面没有经验。

Atomic::cmpxchg & Atomic::cmpxchg_ptr依赖于 OS & CPU & 32bit/64bit。所以 JVM 在这里被拆分。

编辑

正如 steve-O 所指出的,CAS 有其作为 ABA 问题的弱点,因此这里需要内存屏障以确保 CAS 在多线程环境中仍然正确。此外,由于 CAS 需要地址、旧值和新值三个参数,因此此过程需要现代 CPU。

编辑

有了新的C++0x 标准(现在还没有正式发布?),是不是意味着 JVM 就不需要拆分了?至少,在源代码级别。二进制文件仍然可以拆分,但将由 C++ 编译器处理。

4

2 回答 2

5

它是CAS API 的 JNI 包装器,具有IA64 架构内存屏障

编辑:对于 CAS 的描述:

dest比较值进行比较,如果它们匹配,则将交换值分配给dest

这是一个原子操作,这意味着在操作执行时没有其他处理器可以更改dest的值。

此处列出了在没有原子操作的情况下可能发生的典型问题,即“ABA 问题”

http://en.wikipedia.org/wiki/ABA_problem

为什么要使用 CAS 函数?

简单的例子是一个计数器,如果您有多个线程递增一个计数器,请考虑递增过程的作用:

int i;
read the value of i
add one to the current value
save the value back to i.

当另一个处理器读取i的值并在该处理器完成之前保存i + 1时会发生什么?

你最终得到i + 1而不是i + 2

于 2011-08-24T04:13:48.957 回答
1

这里有一些关于

  • 什么是 oop,为什么要压缩它们?


HotSpot 用语中的“oop”或“普通对象指针”是指向对象的托管指针。它通常与本机机器指针大小相同,这意味着 LP64 系统上的 64 位。在 ILP32 系统上,最大堆大小略小于 4Gb,这对于许多应用程序来说是不够的。

  • 哪些 oops 被压缩?

在 ILP32 模式的 JVM 中,或者如果在 LP64 模式下关闭 UseCompressedOops 标志,则所有 oops 都是本机机器字长。

如果 UseCompressedOops 为 true,则堆中的以下 oops 将被压缩:

•每个对象的klass字段 •每个oop实例字段 •oop数组(objArray)的每个元素

有关详细信息,请查看此sun wiki

于 2011-08-25T05:00:09.363 回答