亿贝上海研发中心招聘 广告平台部门大量招人 - 2020/07/22
内部推荐 联系(base64 encoding): eGlhdGlhbkBlYmF5LmNvbQ==
以下是最新(2020/07/22)的职位列表: 具体 JD 见 https://www.ajinga.com/company-detail-new/5790/
内部推荐 联系(base64 encoding): eGlhdGlhbkBlYmF5LmNvbQ==
以下是最新(2020/07/22)的职位列表: 具体 JD 见 https://www.ajinga.com/company-detail-new/5790/
关于 TLAB 的参数
使用如下命令可以看到所有跟 TLAB 相关的参数:
$java -XX:+PrintFlagsFinal -version | grep TLAB
比如我在 JDK 11 上, 可以看到如下有关 TLAB 的参数:
size_t MinTLABSize = 2048 {product} {default}
bool ResizeTLAB = true {pd product} {default}
uintx TLABAllocationWeight = 35 {product} {default}
uintx TLABRefillWasteFraction = 64 {product} {default}
size_t TLABSize = 0 {product} {default}
bool TLABStats = true {product} {default}
uintx TLABWasteIncrement = 4 {product} {default}
uintx TLABWasteTargetPercent = 1 {product} {default}
bool UseTLAB = true {pd product} {default}
bool ZeroTLAB = false {product} {default}
今天在执行 aysnc-profiler 的时候, 遇到无法执行的问题: 为了方便文件清除, 把解压后的文件放到了 /tmp 目录, 然后把 owner 和 权限都加好, 之后切换java 进程的用户去执行, 报 Permission denied.
mkdir /tmp/profiler
tar -C /tmp/profiler -xvf async-profiler-1.7.1-linux-x64.tar.gz
sudo chmod -R 755 /tmp/profiler/*
sudo chown -R appuser /tmp/profiler
sudo su appuser
/tmp/profiler/profile.sh -d 60 -o tree -e cpu -f profile0717.log.html
/tmp/profile/profiler.sh: Permission denied
如果使用 bash 去执行, 则报:
bash /tmp/profiler/profile.sh -d 60 -o tree -e cpu -f profile0717.log.html
/tmp/profile/profiler.sh: line 67: /tmp/profile/build/jattach: Permission denied
既然文件 owner 和 读和执行权限都加好了, 为什么还报错呢?
原来在 /tmp 目录的挂载方式:
appsuer@test-host:/home/appuser$ mount | grep /tmp
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec)
它设置了 noexec 属性. 所以问题就知道出在那里了, 既然这样, 换个目录就解决了.
假设我有如下代码:
String result = "!";
for (int i = 0; i < 1000; i++) {
result += "abc";
}
blackHole.consume(result);
可以看到里面有很多次字符串拼接, 那么这个 String 会被自动优化为 StringBuilder 类型, 使用 append(String) 方法. 具体实现是使用其父类 AbstractStringBuilder 的 append(String) 方法:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
这里的 str.getChars() 就是字符串复制的方法, 就是 String.getChars() 方法, 里面就这么一句重要的:
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
System.arraycopy 是 native 实现:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
这个 native 实现具体就在 openJDK 的 src/share/vm/prims/jvm.cpp 里面:
JVM_ENTRY(void, JVM_ArrayCopy(JNIEnv *env, jclass ignored, jobject src, jint src_pos,
jobject dst, jint dst_pos, jint length))
JVMWrapper("JVM_ArrayCopy");
// Check if we have null pointers
if (src == NULL || dst == NULL) {
THROW(vmSymbols::java_lang_NullPointerException());
}
arrayOop s = arrayOop(JNIHandles::resolve_non_null(src));
arrayOop d = arrayOop(JNIHandles::resolve_non_null(dst));
assert(s->is_oop(), "JVM_ArrayCopy: src not an oop");
assert(d->is_oop(), "JVM_ArrayCopy: dst not an oop");
// Do copy
s->klass()->copy_array(s, src_pos, d, dst_pos, length, thread);
JVM_END
在具体下去, 就是在 src/share/vm/oops/objArrayKlass.cpp 里面的 copyarray 方法:
void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
int dst_pos, int length, TRAPS) {...}
上面这个方法调用了 do_copy 方法, 里面会根据具体的类型去选择具体的 copy 方法. 如果我们只是上面例子的字母, 应该会选择到 src/share/vm/utilities/copy.hpp 里面的各种具体的 copy 方法:
// Assembly code for platforms that need it.
extern "C" {
void _Copy_conjoint_words(HeapWord* from, HeapWord* to, size_t count);
void _Copy_disjoint_words(HeapWord* from, HeapWord* to, size_t count);
void _Copy_conjoint_words_atomic(HeapWord* from, HeapWord* to, size_t count);
void _Copy_disjoint_words_atomic(HeapWord* from, HeapWord* to, size_t count);
void _Copy_aligned_conjoint_words(HeapWord* from, HeapWord* to, size_t count);
void _Copy_aligned_disjoint_words(HeapWord* from, HeapWord* to, size_t count);
void _Copy_conjoint_bytes(void* from, void* to, size_t count);
void _Copy_conjoint_bytes_atomic (void* from, void* to, size_t count);
void _Copy_conjoint_jshorts_atomic(jshort* from, jshort* to, size_t count);
void _Copy_conjoint_jints_atomic (jint* from, jint* to, size_t count);
void _Copy_conjoint_jlongs_atomic (jlong* from, jlong* to, size_t count);
void _Copy_conjoint_oops_atomic (oop* from, oop* to, size_t count);
void _Copy_arrayof_conjoint_bytes (HeapWord* from, HeapWord* to, size_t count);
void _Copy_arrayof_conjoint_jshorts(HeapWord* from, HeapWord* to, size_t count);
void _Copy_arrayof_conjoint_jints (HeapWord* from, HeapWord* to, size_t count);
void _Copy_arrayof_conjoint_jlongs (HeapWord* from, HeapWord* to, size_t count);
void _Copy_arrayof_conjoint_oops (HeapWord* from, HeapWord* to, size_t count);
}
============== 从底向上看 ========
最终这些字符走的是(这里是 X86 架构,也有其它架构的) src/cpu/x86/vm/stubGenerator_x86_64.cpp 的 jshort_disjoint_arraycopy 方法, 那么这些 stub 是定义在:
StubRoutines::_jshort_disjoint_arraycopy
上面这个函数是定义在: src/share/vm/runtime/stubRoutines.hpp 文件里的.
有时候为了让 CPU 贡献最大的能力, 我们会想尽办法让 CPU 在最高频上达到100%使用率, 可是无论怎么优化都达不到100%, 到底问题出在哪里?