Skip to main content

100 posts tagged with "java"

View All Tags

simpleDatetimeformatter vs datetimeformatter

· One min read

SimpleDatetimeFormat 线程不安全是因为这个format持有一个对象,这个对象会被多个线程修改

DateTimeFormatter 线程安全是因为是一个immutable , 不变的量在不同线程是不会有线程安全问题

相关阅读

java mybatis-plus date handler

· 2 min read

背景

堆栈:

setNonNullParameter:33, DateTypeHandler (org.apache.ibatis.type)
setNonNullParameter:28, DateTypeHandler (org.apache.ibatis.type)
setParameter:73, BaseTypeHandler (org.apache.ibatis.type)
setNonNullParameter:67, UnknownTypeHandler (org.apache.ibatis.type)
setParameter:73, BaseTypeHandler (org.apache.ibatis.type)
setParameters:232, MybatisParameterHandler (com.baomidou.mybatisplus.core)
parameterize:94, PreparedStatementHandler (org.apache.ibatis.executor.statement)
parameterize:64, RoutingStatementHandler (org.apache.ibatis.executor.statement)
invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:62, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
invoke:566, Method (java.lang.reflect)
invoke:64, Plugin (org.apache.ibatis.plugin)
parameterize:-1, $Proxy255 (com.sun.proxy)
prepareStatement:88, SimpleExecutor (org.apache.ibatis.executor)
doQuery:62, SimpleExecutor (org.apache.ibatis.executor)
queryFromDatabase:325, BaseExecutor (org.apache.ibatis.executor)
query:156, BaseExecutor (org.apache.ibatis.executor)
query:109, CachingExecutor (org.apache.ibatis.executor)
intercept:81, MybatisPlusInterceptor (com.baomidou.mybatisplus.extension.plugins)
invoke:62, Plugin (org.apache.ibatis.plugin)
query:-1, $Proxy254 (com.sun.proxy)
selectList:151, DefaultSqlSession (org.apache.ibatis.session.defaults)
selectList:145, DefaultSqlSession (org.apache.ibatis.session.defaults)
selectList:140, DefaultSqlSession (org.apache.ibatis.session.defaults)
invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:62, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
invoke:566, Method (java.lang.reflect)
invoke:427, SqlSessionTemplate$SqlSessionInterceptor (org.mybatis.spring)
selectList:-1, $Proxy146 (com.sun.proxy)
selectList:224, SqlSessionTemplate (org.mybatis.spring)
executeForMany:166, MybatisMapperMethod (com.baomidou.mybatisplus.core.override)
execute:77, MybatisMapperMethod (com.baomidou.mybatisplus.core.override)
invoke:148, MybatisMapperProxy$PlainMethodInvoker (com.baomidou.mybatisplus.core.override)
invoke:89, MybatisMapperProxy (com.baomidou.mybatisplus.core.override)
getUserAndSkuByDay:-1, $Proxy215 (com.sun.proxy)
invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:62, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
invoke:566, Method (java.lang.reflect)
invokeJoinpointUsingReflection:344, AopUtils (org.springframework.aop.support)
invokeJoinpoint:198, ReflectiveMethodInvocation (org.springframework.aop.framework)
proceed:163, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:50, DynamicDataSourceAnnotationInterceptor (com.baomidou.dynamic.datasource.aop)
proceed:186, ReflectiveMethodInvocation (org.springframework.aop.framework)
invoke:212, JdkDynamicAopProxy (org.springframework.aop.framework)
getUserAndSkuByDay:-1, $Proxy216 (com.sun.proxy)
testQuery:23, CdpUserBehaviorDataMapperTest (com.patpat.mms.mdp.base.core.service.mapper.cdp)
invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:62, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
invoke:566, Method (java.lang.reflect)
runReflectiveCall:59, FrameworkMethod$1 (org.junit.runners.model)
run:12, ReflectiveCallable (org.junit.internal.runners.model)
invokeExplosively:56, FrameworkMethod (org.junit.runners.model)
evaluate:17, InvokeMethod (org.junit.internal.runners.statements)
evaluate:74, RunBeforeTestExecutionCallbacks (org.springframework.test.context.junit4.statements)
evaluate:84, RunAfterTestExecutionCallbacks (org.springframework.test.context.junit4.statements)
evaluate:75, RunBeforeTestMethodCallbacks (org.springframework.test.context.junit4.statements)
evaluate:86, RunAfterTestMethodCallbacks (org.springframework.test.context.junit4.statements)
evaluate:84, SpringRepeat (org.springframework.test.context.junit4.statements)
runLeaf:366, ParentRunner (org.junit.runners)
runChild:251, SpringJUnit4ClassRunner (org.springframework.test.context.junit4)
runChild:97, SpringJUnit4ClassRunner (org.springframework.test.context.junit4)
run:331, ParentRunner$4 (org.junit.runners)
schedule:79, ParentRunner$1 (org.junit.runners)
runChildren:329, ParentRunner (org.junit.runners)
access$100:66, ParentRunner (org.junit.runners)
evaluate:293, ParentRunner$2 (org.junit.runners)
evaluate:61, RunBeforeTestClassCallbacks (org.springframework.test.context.junit4.statements)
evaluate:70, RunAfterTestClassCallbacks (org.springframework.test.context.junit4.statements)
evaluate:306, ParentRunner$3 (org.junit.runners)
run:413, ParentRunner (org.junit.runners)
run:190, SpringJUnit4ClassRunner (org.springframework.test.context.junit4)
run:137, JUnitCore (org.junit.runner)
startRunnerWithArgs:69, JUnit4IdeaTestRunner (com.intellij.junit4)
execute:38, IdeaTestRunner$Repeater$1 (com.intellij.rt.junit)
repeat:11, TestsRepeater (com.intellij.rt.execution.junit)
startRunnerWithArgs:35, IdeaTestRunner$Repeater (com.intellij.rt.junit)
prepareStreamsAndStart:232, JUnitStarter (com.intellij.rt.junit)
main:55, JUnitStarter (com.intellij.rt.junit)

java oom hprof文件生成时机

· 4 min read

背景

1 有次排查oom问题,发现没有对应的目录,oom后会不生成hprof的dump文件 2 oom后被try catch 后依然可以生成dump的prof文件,所以不是在退出生成hprof文件的,而是在生成这个异常的时候生成dump的hprof文件的

代码

java -Xms50m -Xmx50m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/logs/jvmlogs/java.hprof Main.java

import java.util.ArrayList;
import java.util.List;

public class Main {
public static void main(String[] args) {
List<Object> tem = new ArrayList<>();

boolean test = true;
try {
while (test) {
tem.add(new int[10000000]);
}
}catch (Throwable table){
System.out.println("oom test");
}
System.out.println("afasdfadsf");
}
}

堆栈

Thread 2 "java" hit Breakpoint 1, HeapDumper::dump (this=this@entry=0x7ffff7bfe090, path=path@entry=0x7ffff0803c20 "/home/ubuntu/fasdfd/fadf", out=0x7ffff0000b80, compression=0, overwrite=overwrite@entry=false, num_dump_threads=num_dump_threads@entry=1) at /home/ubuntu/jdk/src/hotspot/share/services/heapDumper.cpp:2383
2383 int HeapDumper::dump(const char* path, outputStream* out, int compression, bool overwrite, uint num_dump_threads) {
(gdb) bt
#0 HeapDumper::dump (this=this@entry=0x7ffff7bfe090, path=path@entry=0x7ffff0803c20 "/home/ubuntu/fasdfd/fadf", out=0x7ffff0000b80, compression=0, overwrite=overwrite@entry=false, num_dump_threads=num_dump_threads@entry=1)
at /home/ubuntu/jdk/src/hotspot/share/services/heapDumper.cpp:2383
#1 0x00007ffff65473a8 in HeapDumper::dump_heap (oome=oome@entry=true) at /home/ubuntu/jdk/src/hotspot/share/services/heapDumper.cpp:2573
#2 0x00007ffff654750e in HeapDumper::dump_heap_from_oome () at /home/ubuntu/jdk/src/hotspot/share/services/heapDumper.cpp:2487
#3 0x00007ffff61e9c78 in report_java_out_of_memory (message=message@entry=0x7ffff75a0d5e "Java heap space") at /home/ubuntu/jdk/src/hotspot/share/utilities/debug.cpp:356
#4 0x00007ffff6c3760d in MemAllocator::Allocation::check_out_of_memory (this=this@entry=0x7ffff7bfe1b0) at /home/ubuntu/jdk/src/hotspot/share/gc/shared/memAllocator.cpp:126
#5 0x00007ffff6c3aac6 in MemAllocator::Allocation::~Allocation (this=0x7ffff7bfe1b0, __in_chrg=<optimized out>) at /home/ubuntu/jdk/src/hotspot/share/gc/shared/memAllocator.cpp:83
#6 MemAllocator::allocate (this=this@entry=0x7ffff7bfe280) at /home/ubuntu/jdk/src/hotspot/share/gc/shared/memAllocator.cpp:375
#7 0x00007ffff72658e7 in CollectedHeap::array_allocate (__the_thread__=0x7ffff0029850, do_zero=true, length=10000000, size=<optimized out>, klass=0x100040d90, this=<optimized out>) at /home/ubuntu/jdk/src/hotspot/share/gc/shared/collectedHeap.inline.hpp:41
#8 TypeArrayKlass::allocate_common (this=this@entry=0x100040d90, length=length@entry=10000000, do_zero=do_zero@entry=true, __the_thread__=__the_thread__@entry=0x7ffff0029850) at /home/ubuntu/jdk/src/hotspot/share/oops/typeArrayKlass.cpp:93
#9 0x00007ffff6d861d9 in TypeArrayKlass::allocate (__the_thread__=0x7ffff0029850, length=10000000, this=<optimized out>) at /home/ubuntu/jdk/src/hotspot/share/oops/typeArrayKlass.hpp:68
#10 oopFactory::new_typeArray (type=type@entry=T_INT, length=length@entry=10000000, __the_thread__=__the_thread__@entry=0x7ffff0029850) at /home/ubuntu/jdk/src/hotspot/share/memory/oopFactory.cpp:93
#11 0x00007ffff662b51a in InterpreterRuntime::newarray (current=0x7ffff0029850, type=T_INT, size=10000000) at /home/ubuntu/jdk/src/hotspot/share/interpreter/interpreterRuntime.cpp:248
#12 0x00007fffe856be1a in ?? ()
#13 0x00007fffe856bd91 in ?? ()
#14 0x00000000fcf98230 in ?? ()
#15 0x00007ffff7bfe3e0 in ?? ()
#16 0x00007fffc9014349 in ?? ()
#17 0x00007ffff7bfe450 in ?? ()
#18 0x00007fffc9014408 in ?? ()
#19 0x0000000000000000 in ?? ()

核心函数是

void report_java_out_of_memory(const char* message) {
static int out_of_memory_reported = 0;

if (Atomic::cmpxchg(&out_of_memory_reported, 0, 1) == 0) {
// create heap dump before OnOutOfMemoryError commands are executed
if (HeapDumpOnOutOfMemoryError) {
tty->print_cr("java.lang.OutOfMemoryError: %s", message);
HeapDumper::dump_heap_from_oome(); // 生成hprof 文件
}

if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
VMError::report_java_out_of_memory(message); // 生成错误信息
}

if (CrashOnOutOfMemoryError) {
tty->print_cr("Aborting due to java.lang.OutOfMemoryError: %s", message);
report_fatal(OOM_JAVA_HEAP_FATAL, __FILE__, __LINE__, "OutOfMemory encountered: %s", message); // catch 导致的
}

if (ExitOnOutOfMemoryError) {
tty->print_cr("Terminating due to java.lang.OutOfMemoryError: %s", message);
os::_exit(3); // quick exit with no cleanup hooks run
}
}
}

如何打开dump文件的

char const* FileWriter::open_writer() {
assert(_fd < 0, "Must not already be open");

_fd = os::create_binary_file(_path, _overwrite);

if (_fd < 0) {
return os::strerror(errno);
}

return NULL;
}

最后调用的是linux 的库函数open64

// jdk/src/hotspot/os/linux/os_linux.cpp
// create binary file, rewriting existing file if required
int os::create_binary_file(const char* path, bool rewrite_existing) {
int oflags = O_WRONLY | O_CREAT;
oflags |= rewrite_existing ? O_TRUNC : O_EXCL;
return ::open64(path, oflags, S_IREAD | S_IWRITE);
}

dump的目录一定要存在,不存在也不会检查

生成hprof文件和exception的时机

bool MemAllocator::Allocation::check_out_of_memory() {
JavaThread* THREAD = _thread; // For exception macros.
assert(!HAS_PENDING_EXCEPTION, "Unexpected exception, will result in uninitialized storage");

if (obj() != NULL) {
return false;
}

const char* message = _overhead_limit_exceeded ? "GC overhead limit exceeded" : "Java heap space";
if (!_thread->in_retryable_allocation()) {
// -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
report_java_out_of_memory(message); ////////////// 生成hprof 文件 , 里面就是上面的一对内容

if (JvmtiExport::should_post_resource_exhausted()) {
JvmtiExport::post_resource_exhausted(
JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP,
message);
}
oop exception = _overhead_limit_exceeded ?
Universe::out_of_memory_error_gc_overhead_limit() : // gc 超过limit 导致的oom的异常
Universe::out_of_memory_error_java_heap(); // 我们平常说的堆内存不足导致oom
THROW_OOP_(exception, true);
} else {
THROW_OOP_(Universe::out_of_memory_error_retry(), true);
}
}

所以是先生成dump文件,再抛异常

相关阅读

java 业务oom排查

· One min read

背景

  • jdk版本:jdk11

之前会请求一个php的内部商品接口服务,现在切换成java的商品接口服务,但是java的代码很多边界有问题,导致oom

现象

cpu 飙升100% ,内存飙升100%,然后直接挂了

排查

开始排查

日志:显示是oom

开始发现没有dump文件,添加dump文件

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/logs/jvmlogs/java.hprof

然后分析,整个堆有个400m和100m的大对象,整个堆也就1G,这两个对象就已经占了50%+ 了

最后确认是sql有问题,把整个表都查出来了

elastic search 编译和调试

· 5 min read

背景

熟悉elastic search

构建

./gradlew localDistro
  • 第一步: 关闭安全相关检查,我本地是http,不需要https
### config/elasticsearch.yml 的这个选项改成false , 这样可以关闭https校验
# Enable security features
xpack.security.enabled: false

  • 改代码 elasticsearch/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ServerProcess.java 添加jdb相关参数:
        // also pass through distribution type
jvmOptions.add("-Des.distribution.type=" + processInfo.sysprops().get("es.distribution.type"));
jvmOptions.add("-agentlib:jdwp=transport=dt_socket,server=y,address=9999"); // 添加这一行 , 让jdb可以调试
  • 运行elasticsearch , 这时候会卡在启动的时候,等待jdb连接
./elasticsearch
  • 使用jdb调试

使用gradle 拉取代码之后,需要获取lucene的代码,并解压到/home/ubuntu/lucene目录

jar -xf /home/ubuntu/.gradle/caches/modules-2/files-2.1/org.apache.lucene/lucene-core/9.7.0/35359f1763c9d7a0f04188c4933311be3c07b60e/lucene-core-9.7.0-sources.jar
## 这里/home/dai/ 是我放elasticsearch 的地方 , `/home/ubuntu/.gradle/caches/modules-2/files-2.1/org.apache.lucene/lucene-core/9.7.0/35359f1763c9d7a0f04188c4933311be3c07b60e/` 是我的gradle 的默认下载路径,可以自己用find去找
jdb -attach 9999 -sourcepath /home/ubuntu/elasticsearch/distribution/tools/cli-launcher/src/main/java/:/home/ubuntu/elasticsearch/server/src/main/java/:/home/ubuntu/lucene/
  • 断点
stop in org.elasticsearch.rest.action.search.RestSearchAction.prepareRequest

堆栈

使用jdb调试:

断点是:stop in org.elasticsearch.rest.action.search.RestSearchAction.prepareRequest

Breakpoint hit: 
Breakpoint hit: "thread=elasticsearch[myhost][transport_worker][T#5]", org.elasticsearch.rest.action.search.RestSearchAction.prepareRequest(), line=100 bci=0
100 if (request.hasParam("min_compatible_shard_node")) {

elasticsearch[myhost][transport_worker][T#5][1] where
[1] org.elasticsearch.rest.action.search.RestSearchAction.prepareRequest (RestSearchAction.java:100)
[2] org.elasticsearch.rest.BaseRestHandler.handleRequest (BaseRestHandler.java:80)
[3] org.elasticsearch.xpack.security.rest.SecurityRestFilter.doHandleRequest (SecurityRestFilter.java:96)
[4] org.elasticsearch.xpack.security.rest.SecurityRestFilter.handleRequest (SecurityRestFilter.java:76)
[5] org.elasticsearch.rest.RestController.dispatchRequest (RestController.java:414)
[6] org.elasticsearch.rest.RestController.tryAllHandlers (RestController.java:543)
[7] org.elasticsearch.rest.RestController.dispatchRequest (RestController.java:316)
[8] org.elasticsearch.http.AbstractHttpServerTransport.dispatchRequest (AbstractHttpServerTransport.java:453)
[9] org.elasticsearch.http.AbstractHttpServerTransport.handleIncomingRequest (AbstractHttpServerTransport.java:549)
[10] org.elasticsearch.http.AbstractHttpServerTransport.incomingRequest (AbstractHttpServerTransport.java:426)
[11] org.elasticsearch.http.netty4.Netty4HttpPipeliningHandler.handlePipelinedRequest (Netty4HttpPipeliningHandler.java:128)
[12] org.elasticsearch.http.netty4.Netty4HttpPipeliningHandler.channelRead (Netty4HttpPipeliningHandler.java:118)
[13] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:442)
[14] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:420)
[15] io.netty.channel.AbstractChannelHandlerContext.fireChannelRead (AbstractChannelHandlerContext.java:412)
[16] io.netty.handler.codec.MessageToMessageDecoder.channelRead (MessageToMessageDecoder.java:103)
[17] io.netty.handler.codec.MessageToMessageCodec.channelRead (MessageToMessageCodec.java:111)
[18] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:442)
[19] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:420)
[20] io.netty.channel.AbstractChannelHandlerContext.fireChannelRead (AbstractChannelHandlerContext.java:412)
[21] io.netty.handler.codec.MessageToMessageDecoder.channelRead (MessageToMessageDecoder.java:103)
[22] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:444)
[23] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:420)
[24] io.netty.channel.AbstractChannelHandlerContext.fireChannelRead (AbstractChannelHandlerContext.java:412)
[25] io.netty.handler.codec.MessageToMessageDecoder.channelRead (MessageToMessageDecoder.java:103)
[26] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:444)
[27] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:420)
[28] io.netty.channel.AbstractChannelHandlerContext.fireChannelRead (AbstractChannelHandlerContext.java:412)
[29] io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead (ByteToMessageDecoder.java:346)
[30] io.netty.handler.codec.ByteToMessageDecoder.channelRead (ByteToMessageDecoder.java:318)
[31] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:444)
[32] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:420)
[33] io.netty.channel.AbstractChannelHandlerContext.fireChannelRead (AbstractChannelHandlerContext.java:412)
[34] io.netty.handler.codec.MessageToMessageDecoder.channelRead (MessageToMessageDecoder.java:103)
[35] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:444)
[36] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:420)
[37] io.netty.channel.AbstractChannelHandlerContext.fireChannelRead (AbstractChannelHandlerContext.java:412)
[38] io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead (DefaultChannelPipeline.java:1,410)
[39] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:440)
[40] io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead (AbstractChannelHandlerContext.java:420)
[41] io.netty.channel.DefaultChannelPipeline.fireChannelRead (DefaultChannelPipeline.java:919)
[42] io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read (AbstractNioByteChannel.java:166)
[43] io.netty.channel.nio.NioEventLoop.processSelectedKey (NioEventLoop.java:788)
[44] io.netty.channel.nio.NioEventLoop.processSelectedKeysPlain (NioEventLoop.java:689)
[45] io.netty.channel.nio.NioEventLoop.processSelectedKeys (NioEventLoop.java:652)
[46] io.netty.channel.nio.NioEventLoop.run (NioEventLoop.java:562)
[47] io.netty.util.concurrent.SingleThreadEventExecutor$4.run (SingleThreadEventExecutor.java:997)
[48] io.netty.util.internal.ThreadExecutorMap$2.run (ThreadExecutorMap.java:74)
[49] java.lang.Thread.runWith (Thread.java:1,636)
[50] java.lang.Thread.run (Thread.java:1,623)

query phase

elasticsearch[myhost][search][T#7][1] where
[1] org.elasticsearch.search.query.QueryPhase.execute (QueryPhase.java:62)
[2] org.elasticsearch.search.SearchService.loadOrExecuteQueryPhase (SearchService.java:516)
[3] org.elasticsearch.search.SearchService.executeQueryPhase (SearchService.java:668)
[4] org.elasticsearch.search.SearchService.lambda$executeQueryPhase$2 (SearchService.java:541)
[5] org.elasticsearch.search.SearchService$$Lambda$7604/0x00007fceb1297320.get (null)
[6] org.elasticsearch.action.ActionRunnable$2.accept (ActionRunnable.java:51)
[7] org.elasticsearch.action.ActionRunnable$2.accept (ActionRunnable.java:48)
[8] org.elasticsearch.action.ActionRunnable$3.doRun (ActionRunnable.java:73)
[9] org.elasticsearch.common.util.concurrent.AbstractRunnable.run (AbstractRunnable.java:26)
[10] org.elasticsearch.common.util.concurrent.TimedRunnable.doRun (TimedRunnable.java:33)
[11] org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun (ThreadContext.java:983)
[12] org.elasticsearch.common.util.concurrent.AbstractRunnable.run (AbstractRunnable.java:26)
[13] java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1,144)
[14] java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:642)
[15] java.lang.Thread.runWith (Thread.java:1,636)
[16] java.lang.Thread.run (Thread.java:1,623)
elasticsearch[myhost][search][T#7][1]

查看reader

Breakpoint hit: "thread=elasticsearch[myhost][search][T#7]", org.elasticsearch.search.query.QueryPhase.addCollectorsAndSearch(), line=150 bci=0
150 final ContextIndexSearcher searcher = searchContext.searcher();

elasticsearch[myhost][search][T#7][1] next
>
Step completed: "thread=elasticsearch[myhost][search][T#7]", org.elasticsearch.search.query.QueryPhase.addCollectorsAndSearch(), line=151 bci=5
151 final IndexReader reader = searcher.getIndexReader();

elasticsearch[myhost][search][T#7][1] next
>
Step completed: "thread=elasticsearch[myhost][search][T#7]", org.elasticsearch.search.query.QueryPhase.addCollectorsAndSearch(), line=152 bci=10
152 QuerySearchResult queryResult = searchContext.queryResult();

elasticsearch[myhost][search][T#7][1] print reader
reader = "ExitableDirectoryReader(FilterLeafReader(FieldUsageTrackingLeafReader(reader=FilterLeafReader(_0(9.7.0):c1:[diagnostics={timestamp=1694357055349, source=flush, lucene.version=9.7.0, os.version=6.2.0-31-generic, os.arch=amd64, os=Linux, java.vendor=Oracle Corporation, java.runtime.version=20.0.2+9-78}]:[attributes={Lucene90StoredFieldsFormat.mode=BEST_SPEED}] :id=bv125vla2ovjxnipt5j9ssmby))))"
elasticsearch[myhost][search][T#7][1]
elasticsearch[myhost][search][T#7][1] print query
query = "age:38"
elasticsearch[myhost][search][T#7][1] step in
>
Step completed: "thread=elasticsearch[myhost][search][T#7]", org.elasticsearch.search.internal.ContextIndexSearcher.search(), line=340 bci=0
340 final C firstCollector = collectorManager.newCollector();

elasticsearch[myhost][search][T#7][1] where
[1] org.elasticsearch.search.internal.ContextIndexSearcher.search (ContextIndexSearcher.java:340)
[2] org.elasticsearch.search.query.QueryPhase.addCollectorsAndSearch (QueryPhase.java:206)
[3] org.elasticsearch.search.query.QueryPhase.executeQuery (QueryPhase.java:134)
[4] org.elasticsearch.search.query.QueryPhase.execute (QueryPhase.java:63)
[5] org.elasticsearch.search.SearchService.loadOrExecuteQueryPhase (SearchService.java:516)
[6] org.elasticsearch.search.SearchService.executeQueryPhase (SearchService.java:668)
[7] org.elasticsearch.search.SearchService.lambda$executeQueryPhase$2 (SearchService.java:541)
[8] org.elasticsearch.search.SearchService$$Lambda$7604/0x00007fceb1297320.get (null)
[9] org.elasticsearch.action.ActionRunnable$2.accept (ActionRunnable.java:51)
[10] org.elasticsearch.action.ActionRunnable$2.accept (ActionRunnable.java:48)
[11] org.elasticsearch.action.ActionRunnable$3.doRun (ActionRunnable.java:73)
[12] org.elasticsearch.common.util.concurrent.AbstractRunnable.run (AbstractRunnable.java:26)
[13] org.elasticsearch.common.util.concurrent.TimedRunnable.doRun (TimedRunnable.java:33)
[14] org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun (ThreadContext.java:983)
[15] org.elasticsearch.common.util.concurrent.AbstractRunnable.run (AbstractRunnable.java:26)
[16] java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1,144)
[17] java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:642)
[18] java.lang.Thread.runWith (Thread.java:1,636)
[19] java.lang.Thread.run (Thread.java:1,623)

bulkScorer 和Scorer

核心变成了这两个函数:

  • bulkScorer
  • scorer
           BulkScorer bulkScorer = weight.bulkScorer(ctx);
if (bulkScorer != null) {
if (cancellable.isEnabled()) {
bulkScorer = new CancellableBulkScorer(bulkScorer, cancellable::checkCancelled);
}
try {
bulkScorer.score(leafCollector, liveDocs);
} catch (CollectionTerminatedException e) {
...
}

这里的weight:

elasticsearch[ubuntu-Vostro-3690][search_worker][T#2][1] dump weight
weight = {
similarity: instance of org.elasticsearch.index.similarity.SimilarityService$PerFieldSimilarity(id=25223)
simScorer: instance of org.apache.lucene.search.similarities.BM25Similarity$BM25Scorer(id=25224)
termStates: instance of org.apache.lucene.index.TermStates(id=25225)
scoreMode: instance of org.apache.lucene.search.ScoreMode(id=25226)
$assertionsDisabled: true
this$0: instance of org.apache.lucene.search.TermQuery(id=25227)
org.apache.lucene.search.Weight.parentQuery: instance of org.apache.lucene.search.TermQuery(id=25227)
}

搜索过程

elasticsearch[myhost][search_worker][T#5][1] list
246 // float. And then monotonicity is preserved through composition via
247 // x -> 1 + x and x -> 1 - 1/x.
248 // Finally we expand weight * (1 - 1 / (1 + freq * 1/norm)) to
249 // weight - weight / (1 + freq * 1/norm), which runs slightly faster.
250 => float normInverse = cache[((byte) encodedNorm) & 0xFF];
251 return weight - weight / (1f + freq * normInverse);
252 }
253
254 @Override
255 public Explanation explain(Explanation freq, long encodedNorm) {
elasticsearch[myhost][search_worker][T#5][1] where
[1] org.apache.lucene.search.similarities.BM25Similarity$BM25Scorer.score (BM25Similarity.java:250)
[2] org.apache.lucene.search.LeafSimScorer.score (LeafSimScorer.java:60)
[3] org.apache.lucene.search.TermScorer.score (TermScorer.java:75)
[4] org.apache.lucene.search.TopScoreDocCollector$SimpleTopScoreDocCollector$1.collect (TopScoreDocCollector.java:73)
[5] org.apache.lucene.search.Weight$DefaultBulkScorer.scoreRange (Weight.java:274)
[6] org.apache.lucene.search.Weight$DefaultBulkScorer.score (Weight.java:254)
[7] org.elasticsearch.search.internal.CancellableBulkScorer.score (CancellableBulkScorer.java:45)
[8] org.apache.lucene.search.BulkScorer.score (BulkScorer.java:38)
[9] org.elasticsearch.search.internal.ContextIndexSearcher.searchLeaf (ContextIndexSearcher.java:538)
[10] org.elasticsearch.search.internal.ContextIndexSearcher.search (ContextIndexSearcher.java:480)
[11] org.elasticsearch.search.internal.ContextIndexSearcher.lambda$search$4 (ContextIndexSearcher.java:396)
[12] org.elasticsearch.search.internal.ContextIndexSearcher$$Lambda$7626/0x00007fceb12a4e58.call (null)
[13] java.util.concurrent.FutureTask.run (FutureTask.java:317)
[14] org.elasticsearch.common.util.concurrent.TimedRunnable.doRun (TimedRunnable.java:33)
[15] org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun (ThreadContext.java:983)
[16] org.elasticsearch.common.util.concurrent.AbstractRunnable.run (AbstractRunnable.java:26)
[17] java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1,144)
[18] java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:642)
[19] java.lang.Thread.runWith (Thread.java:1,636)
[20] java.lang.Thread.run (Thread.java:1,623)

es 常用 crud

  • 写入
curl -XPOST http://localhost:9200/test/_doc -H "Content-Type: application/json" -d  '{"name":"John Smith","age":"38"}'
  • 查询
curl -X GET  -H "Content-Type: application/json"    http://localhost:9200/test/_search -d '{"query":{"match":{"age":"38"}}}'

相关阅读

java branch bytecode

· 9 min read

背景

了解各种分支跳转

注释

(gdb) x/30i 0x7fffe10176ab

0x7fffe10176ab: mov -0x18(%rbp),%rcx ## __ get_method(rcx); // rcx holds method , rbp-0x18 就是方法地址
0x7fffe10176af: mov -0x28(%rbp),%rax ## __ profile_taken_branch(rax, rbx); // rax holds updated MDP, rbx 一直到 0x7fffe10176d0都是profile_taken_branch
0x7fffe10176b3: test %rax,%rax
0x7fffe10176b6: je 0x7fffe10176d4
0x7fffe10176bc: mov 0x8(%rax),%rbx
0x7fffe10176c0: add $0x1,%rbx
0x7fffe10176c4: sbb $0x0,%rbx
0x7fffe10176c8: mov %rbx,0x8(%rax)
0x7fffe10176cc: add 0x10(%rax),%rax
0x7fffe10176d0: mov %rax,-0x28(%rbp)
0x7fffe10176d4: movswl 0x1(%r13),%edx ## __ movl(rdx, at_bcp(1)); r13指向当前要取的字节码指令的地址
0x7fffe10176d9: bswap %edx ##__ bswapl(rdx);
0x7fffe10176db: sar $0x10,%edx ## __ sarl(rdx, 16);
0x7fffe10176de: movslq %edx,%rdx ## LP64_ONLY(__ movl2ptr(rdx, rdx));
0x7fffe10176e1: add %rdx,%r13 ## __ addptr(rbcp, rdx); // Adjust the bcp in r13 by the displacement in rdx
0x7fffe10176e4: test %edx,%edx ## 判断是不是 0 ,是0 就ZF=1 ,SF
0x7fffe10176e6: jns 0x7fffe10176ec ## 大于等于0 , 跳转到0x7fffe10176ec
0x7fffe10176ec: mov 0x20(%rcx),%rax
0x7fffe10176ec: mov 0x20(%rcx),%rax ## __ movptr(rax, Address(rcx, Method::method_counters_offset()));
0x7fffe10176f0: test %rax,%rax ## __ testptr(rax, rax);
0x7fffe10176f3: jne 0x7fffe10176f9 ## ZF!=0 跳转, 也就是rax >0 跳转 __ jcc(Assembler::notZero, has_counters);
0x7fffe10176f9: push %rdx ## __ push(rdx);
0x7fffe10176fa: push %rcx ## __ push(rcx);
0x7fffe10176fb: call 0x7fffe1017705 ## begin , __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters),
rcx); 一直到0x7fffe1017828
0x7fffe1017700: jmp 0x7fffe1017829
0x7fffe1017705: mov %rcx,%rsi
0x7fffe1017708: lea 0x8(%rsp),%rax
0x7fffe101770d: mov %r13,-0x40(%rbp)
0x7fffe1017711: cmpq $0x0,-0x10(%rbp)
0x7fffe1017719: je 0x7fffe1017733
0x7fffe101771f: movabs $0x7ffff71becc8,%rdi
0x7fffe1017729: and $0xfffffffffffffff0,%rsp
0x7fffe101772d:
call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1017732: hlt
0x7fffe1017733: push %r10
0x7fffe1017735:
cmp 0x16aef7c4(%rip),%r12 # 0x7ffff7b06f00 <_ZN14CompressedOops11_narrow_oopE>
0x7fffe101773c: je 0x7fffe1017756
0x7fffe1017742: movabs $0x7ffff7311c28,%rdi
0x7fffe101774c: and $0xfffffffffffffff0,%rsp
0x7fffe1017750:
call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1017755: hlt
0x7fffe1017756: pop %r10
0x7fffe1017758: mov %r15,%rdi
0x7fffe101775b: vzeroupper
0x7fffe101775e: mov %rbp,0x2d0(%r15)
0x7fffe1017765: mov %rax,0x2c0(%r15)
0x7fffe101776c: test $0xf,%esp
0x7fffe1017772: je 0x7fffe101778a
0x7fffe1017778: sub $0x8,%rsp
0x7fffe101777c:
call 0x7ffff65d4a46 <_ZN18InterpreterRuntime21build_method_countersEP10JavaThreadP6Method>
0x7fffe1017781: add $0x8,%rsp
0x7fffe1017785: jmp 0x7fffe101778f
0x7fffe101778a:
call 0x7ffff65d4a46 <_ZN18InterpreterRuntime21build_method_countersEP10JavaThreadP6Method>
0x7fffe101778f: push %rax
0x7fffe1017790: push %rdi
0x7fffe1017791: push %rsi
0x7fffe1017792: push %rdx
0x7fffe1017793: push %rcx
0x7fffe1017794: push %r8
0x7fffe1017796: push %r9
0x7fffe1017798: push %r10
0x7fffe101779a: push %r11
0x7fffe101779c: test $0xf,%esp
0x7fffe10177a2: je 0x7fffe10177ba
0x7fffe10177a8: sub $0x8,%rsp
0x7fffe10177ac: call 0x7ffff5d1c04e <_ZN6Thread7currentEv>
0x7fffe10177b1: add $0x8,%rsp
0x7fffe10177b5: jmp 0x7fffe10177bf
0x7fffe10177ba: call 0x7ffff5d1c04e <_ZN6Thread7currentEv>
0x7fffe10177bf: pop %r11
0x7fffe10177c1: pop %r10
0x7fffe10177c3: pop %r9
0x7fffe10177c5: pop %r8
0x7fffe10177c7: pop %rcx
0x7fffe10177c8: pop %rdx
0x7fffe10177c9: pop %rsi
0x7fffe10177ca: pop %rdi
0x7fffe10177cb: cmp %rax,%r15
0x7fffe10177ce: je 0x7fffe10177e8
0x7fffe10177d4: movabs $0x7ffff7311da0,%rdi
0x7fffe10177de: and $0xfffffffffffffff0,%rsp
0x7fffe10177e2:
call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe10177e7: hlt
0x7fffe10177e8: pop %rax
0x7fffe10177e9: movq $0x0,0x2c0(%r15)
0x7fffe10177f4: movq $0x0,0x2d0(%r15)
0x7fffe10177ff: movq $0x0,0x2c8(%r15)
0x7fffe101780a: vzeroupper
0x7fffe101780d: cmpq $0x0,0x8(%r15)
0x7fffe1017815: je 0x7fffe1017820
0x7fffe101781b: jmp 0x7fffe1000c20
0x7fffe1017820: mov -0x40(%rbp),%r13
0x7fffe1017824: mov -0x38(%rbp),%r14
0x7fffe1017828: ret ### end __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters),
rcx);
0x7fffe1017829: pop %rcx ### __ pop(rcx);
0x7fffe101782a: pop %rdx ## __ pop(rdx);
0x7fffe101782b: mov 0x20(%rcx),%rax ## __ movptr(rax, Address(rcx, Method::method_counters_offset()));
0x7fffe101782f: test %rax,%rax ## __ testptr(rax, rax);
0x7fffe1017832: je 0x7fffe1017838 ## __ jcc(Assembler::zero, dispatch);
0x7fffe1017838: mov 0x18(%rcx),%rbx ## __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); // Are we profiling?
0x7fffe101783c: test %rbx,%rbx ## __ testptr(rbx, rbx);
0x7fffe101783f: je 0x7fffe1017841 ## __ jccb(Assembler::zero, no_mdo);
0x7fffe1017841: mov 0x130(%rbx),%eax ## 一直到0x7fffe1017856 都是 __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero,
UseOnStackReplacement ? &backedge_counter_overflow : NULL);
0x7fffe1017847: add $0x2,%eax
0x7fffe101784a: mov %eax,0x130(%rbx)
0x7fffe1017850: and 0x144(%rbx),%eax
0x7fffe1017856: je 0x7fffe101785c
0x7fffe101785c: jmp 0x7fffe1017861 ## __ jmp(dispatch);
0x7fffe1017861: mov 0x20(%rcx),%rcx ## __ movptr(rcx, Address(rcx, Method::method_counters_offset()));
0x7fffe1017865: mov 0x10(%rcx),%eax ### __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask,rax, false, Assembler::zero, UseOnStackReplacement ? &backedge_counter_overflow : NULL);
0x7fffe1017868: add $0x2,%eax
0x7fffe101786b: mov %eax,0x10(%rcx)
0x7fffe101786e: and 0x2c(%rcx),%eax
0x7fffe1017871: je 0x7fffe1017877
0x7fffe1017877: movzbl 0x0(%r13),%ebx ### // Pre-load the next target bytecode into rbx __ load_unsigned_byte(rbx, Address(rbcp, 0));
0x7fffe101787c: testb $0x1,0x388(%r15) ### // continue with the bytecode @ target
### // rax: return bci for jsr's, unused otherwise
###// rbx: target bytecode
###// r13: target bcp
### // __ dispatch_only(vtos, true); 从0x7fffe101787c 到 0x7fffe101789c
0x7fffe1017884: je 0x7fffe1017892
0x7fffe1017886: movabs $0x7ffff7bd68a0,%r10
0x7fffe1017890: jmp 0x7fffe101789c
0x7fffe1017892: movabs $0x7ffff7bcc8a0,%r10
0x7fffe101789c: jmp *(%r10,%rbx,8)
0x7fffe10178a0: neg %rdx ## __ negptr(rdx);
0x7fffe10178a3: add %r13,%rdx ## __ addptr(rdx, rbcp); // branch bcp
0x7fffe10178a6: call 0x7fffe10178b0 ## 从 0x7fffe10178a6 到0x7fffe10179d3 都是call_VM
## __ call_VM(noreg,
## CAST_FROM_FN_PTR(address,
## InterpreterRuntime::frequency_counter_overflow),
## rdx);
0x7fffe10178ab: jmp 0x7fffe10179d4
0x7fffe10178b0: mov %rdx,%rsi
0x7fffe10178b3: lea 0x8(%rsp),%rax
0x7fffe10178b8: mov %r13,-0x40(%rbp)
0x7fffe10178bc: cmpq $0x0,-0x10(%rbp)
0x7fffe10178c4: je 0x7fffe10178de
0x7fffe10178ca: movabs $0x7ffff71becc8,%rdi
0x7fffe10178d4: and $0xfffffffffffffff0,%rsp
0x7fffe10178d8: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe10178dd: hlt
0x7fffe10178de: push %r10
0x7fffe10178e0: cmp 0x16aef619(%rip),%r12 # 0x7ffff7b06f00 <_ZN14CompressedOops11_narrow_oopE>
0x7fffe10178e7: je 0x7fffe1017901
0x7fffe10178ed: movabs $0x7ffff7311c28,%rdi
0x7fffe10178f7: and $0xfffffffffffffff0,%rsp
0x7fffe10178fb: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1017900: hlt
0x7fffe1017901: pop %r10
0x7fffe1017903: mov %r15,%rdi
0x7fffe1017906: vzeroupper
0x7fffe1017909: mov %rbp,0x2d0(%r15)
0x7fffe1017910: mov %rax,0x2c0(%r15)
0x7fffe1017917: test $0xf,%esp
0x7fffe101791d: je 0x7fffe1017935
0x7fffe1017923: sub $0x8,%rsp
0x7fffe1017927: call 0x7ffff65d3eb4 <_ZN18InterpreterRuntime26frequency_counter_overflowEP10JavaThreadPh>
0x7fffe101792c: add $0x8,%rsp
0x7fffe1017930: jmp 0x7fffe101793a
0x7fffe1017935: call 0x7ffff65d3eb4 <_ZN18InterpreterRuntime26frequency_counter_overflowEP10JavaThreadPh>
0x7fffe101793a: push %rax
0x7fffe101793b: push %rdi
0x7fffe101793c: push %rsi
0x7fffe101793d: push %rdx
0x7fffe101793e: push %rcx
0x7fffe101793f: push %r8
0x7fffe1017941: push %r9
0x7fffe1017943: push %r10
0x7fffe1017945: push %r11
0x7fffe1017947: test $0xf,%esp
0x7fffe101794d: je 0x7fffe1017965
0x7fffe1017953: sub $0x8,%rsp
0x7fffe1017957: call 0x7ffff5d1c04e <_ZN6Thread7currentEv>
0x7fffe101795c: add $0x8,%rsp
0x7fffe1017960: jmp 0x7fffe101796a
0x7fffe1017965: call 0x7ffff5d1c04e <_ZN6Thread7currentEv>
0x7fffe101796a: pop %r11
0x7fffe101796c: pop %r10
0x7fffe101796e: pop %r9
0x7fffe1017970: pop %r8
0x7fffe1017972: pop %rcx
0x7fffe1017973: pop %rdx
0x7fffe1017974: pop %rsi
0x7fffe1017975: pop %rdi
0x7fffe1017976: cmp %rax,%r15
0x7fffe1017979: je 0x7fffe1017993
0x7fffe101797f: movabs $0x7ffff7311da0,%rdi
0x7fffe1017989: and $0xfffffffffffffff0,%rsp
0x7fffe101798d: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1017992: hlt
0x7fffe1017993: pop %rax
0x7fffe1017994: movq $0x0,0x2c0(%r15)
0x7fffe101799f: movq $0x0,0x2d0(%r15)
0x7fffe10179aa: movq $0x0,0x2c8(%r15)
0x7fffe10179b5: vzeroupper
0x7fffe10179b8: cmpq $0x0,0x8(%r15)
0x7fffe10179c0: je 0x7fffe10179cb
0x7fffe10179c6: jmp 0x7fffe1000c20
0x7fffe10179cb: mov -0x40(%rbp),%r13
0x7fffe10179cf: mov -0x38(%rbp),%r14
0x7fffe10179d3: ret
## // rax: osr nmethod (osr ok) or NULL (osr not possible)
## // rdx: scratch
## // r14: locals pointer
## // r13: bcp
0x7fffe10179d4: test %rax,%rax ## __ testptr(rax, rax); // test result
0x7fffe10179d7: je 0x7fffe1017877 ## __ jcc(Assembler::zero, dispatch); // no osr if null
0x7fffe10179dd: cmpb $0x0,0x14b(%rax) ## // nmethod may have been invalidated (VM may block upon call_VM return) __ cmpb(Address(rax, nmethod::state_offset()), nmethod::in_use);
0x7fffe10179e4: jne 0x7fffe1017877 ## __ jcc(Assembler::notEqual, dispatch);
### // We have the address of an on stack replacement routine in rax.
### // In preparation of invoking it, first we must migrate the locals
### // and monitors from off the interpreter frame on the stack.
### // Ensure to save the osr nmethod over the migration call,
### // it will be preserved in rbx.
0x7fffe10179ea: mov %rax,%rbx ### __ mov(rbx, rax);

0x7fffe10179ed: call 0x7fffe10179f7 ### 从 0x7fffe10179ed 0x7fffe1017b17 都是 call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin));
0x7fffe10179f2: jmp 0x7fffe1017b18
0x7fffe10179f7: lea 0x8(%rsp),%rax
0x7fffe10179fc: mov %r13,-0x40(%rbp)
0x7fffe1017a00: cmpq $0x0,-0x10(%rbp)
0x7fffe1017a08: je 0x7fffe1017a22
0x7fffe1017a0e: movabs $0x7ffff71becc8,%rdi
0x7fffe1017a18: and $0xfffffffffffffff0,%rsp
0x7fffe1017a1c: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1017a21: hlt
0x7fffe1017a22: push %r10
0x7fffe1017a24: cmp 0x16aef4d5(%rip),%r12 # 0x7ffff7b06f00 <_ZN14CompressedOops11_narrow_oopE>
0x7fffe1017a2b: je 0x7fffe1017a45
0x7fffe1017a31: movabs $0x7ffff7311c28,%rdi
0x7fffe1017a3b: and $0xfffffffffffffff0,%rsp
0x7fffe1017a3f: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1017a44: hlt
0x7fffe1017a45: pop %r10
0x7fffe1017a47: mov %r15,%rdi
0x7fffe1017a4a: vzeroupper
0x7fffe1017a4d: mov %rbp,0x2d0(%r15)
0x7fffe1017a54: mov %rax,0x2c0(%r15)
0x7fffe1017a5b: test $0xf,%esp
0x7fffe1017a61: je 0x7fffe1017a79
0x7fffe1017a67: sub $0x8,%rsp
0x7fffe1017a6b: call 0x7ffff6bcdb22 <_ZN13SharedRuntime19OSR_migration_beginEP10JavaThread>
0x7fffe1017a70: add $0x8,%rsp
0x7fffe1017a74: jmp 0x7fffe1017a7e
0x7fffe1017a79: call 0x7ffff6bcdb22 <_ZN13SharedRuntime19OSR_migration_beginEP10JavaThread>
0x7fffe1017a7e: push %rax
0x7fffe1017a7f: push %rdi
0x7fffe1017a80: push %rsi
0x7fffe1017a81: push %rdx
0x7fffe1017a82: push %rcx
0x7fffe1017a83: push %r8
0x7fffe1017a85: push %r9
0x7fffe1017a87: push %r10
0x7fffe1017a89: push %r11
0x7fffe1017a8b: test $0xf,%esp
0x7fffe1017a91: je 0x7fffe1017aa9
0x7fffe1017a97: sub $0x8,%rsp
0x7fffe1017a9b: call 0x7ffff5d1c04e <_ZN6Thread7currentEv>
0x7fffe1017aa0: add $0x8,%rsp
0x7fffe1017aa4: jmp 0x7fffe1017aae
0x7fffe1017aa9: call 0x7ffff5d1c04e <_ZN6Thread7currentEv>
0x7fffe1017aae: pop %r11
0x7fffe1017ab0: pop %r10
0x7fffe1017ab2: pop %r9
0x7fffe1017ab4: pop %r8
0x7fffe1017ab6: pop %rcx
0x7fffe1017ab7: pop %rdx
0x7fffe1017ab8: pop %rsi
0x7fffe1017ab9: pop %rdi
0x7fffe1017aba: cmp %rax,%r15
0x7fffe1017abd: je 0x7fffe1017ad7
0x7fffe1017ac3: movabs $0x7ffff7311da0,%rdi
0x7fffe1017acd: and $0xfffffffffffffff0,%rsp
0x7fffe1017ad1: call 0x7ffff694f3c0 <_ZN14MacroAssembler7debug64EPclPl>
0x7fffe1017ad6: hlt
0x7fffe1017ad7: pop %rax
0x7fffe1017ad8: movq $0x0,0x2c0(%r15)
0x7fffe1017ae3: movq $0x0,0x2d0(%r15)
0x7fffe1017aee: movq $0x0,0x2c8(%r15)
0x7fffe1017af9: vzeroupper
0x7fffe1017afc: cmpq $0x0,0x8(%r15)
0x7fffe1017b04: je 0x7fffe1017b0f
0x7fffe1017b0a: jmp 0x7fffe1000c20
0x7fffe1017b0f: mov -0x40(%rbp),%r13
0x7fffe1017b13: mov -0x38(%rbp),%r14
0x7fffe1017b17: ret
0x7fffe1017b18: mov %rax,%rsi ## LP64_ONLY(__ mov(j_rarg0, rax));
0x7fffe1017b1b: mov -0x8(%rbp),%rdx ## __ movptr(sender_sp, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp
0x7fffe1017b1f: leave ## __ leave(); // remove frame anchor
0x7fffe1017b20: pop %rcx ## __ pop(retaddr); // get return address
0x7fffe1017b21: mov %rdx,%rsp ## __ mov(rsp, sender_sp); // set sp to sender sp
0x7fffe1017b24: and $0xfffffffffffffff0,%rsp ## // Ensure compiled code always sees stack at proper alignment __ andptr(rsp, -(StackAlignmentInBytes));
0x7fffe1017b28: push %rcx ## // push the return address __ push(retaddr);
0x7fffe1017b29: jmp *0xf8(%rbx) ## __ jmp(Address(rbx, nmethod::osr_entry_point_offset()));

完整堆栈

(gdb) bt
#0 TemplateTable::branch (is_jsr=false, is_wide=false)
at /home/dai/jdk/src/hotspot/cpu/x86/templateTable_x86.cpp:2188
#1 0x00007ffff6d74ce0 in TemplateTable::if_0cmp (cc=TemplateTable::equal)
at /home/dai/jdk/src/hotspot/cpu/x86/templateTable_x86.cpp:2302
#2 0x00007ffff6d66161 in Template::generate (
this=0x7ffff7bd8ce0 <TemplateTable::_template_table+4896>,
masm=0x7ffff0029588)
at /home/dai/jdk/src/hotspot/share/interpreter/templateTable.cpp:62
#3 0x00007ffff6d59a3c in TemplateInterpreterGenerator::generate_and_dispatch (
this=0x7ffff59fea10,
t=0x7ffff7bd8ce0 <TemplateTable::_template_table+4896>, tos_out=vtos)
at /home/dai/jdk/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp:380
#4 0x00007ffff6d59572 in TemplateInterpreterGenerator::set_short_entry_points
(this=0x7ffff59fea10,
t=0x7ffff7bd8ce0 <TemplateTable::_template_table+4896>,
bep=@0x7ffff59fe398: 0x7fffe1008f14 "H\277h\260N\367\377\177",
cep=@0x7ffff59fe3a0: 0x7fffe1008f14 "H\277h\260N\367\377\177",
sep=@0x7ffff59fe3a8: 0x7fffe1008f14 "H\277h\260N\367\377\177",
aep=@0x7ffff59fe3b0: 0x7fffe1008f14 "H\277h\260N\367\377\177",
iep=@0x7ffff59fe3b8: 0x7fffe1017627 "PSQRH\213M\330H\205\311\017\204g",
lep=@0x7ffff59fe3c0: 0x7fffe1008f14 "H\277h\260N\367\377\177",
fep=@0x7ffff59fe3c8: 0x7fffe1008f14 "H\277h\260N\367\377\177",
--Type <RET> for more, q to quit, c to continue without paging--
dep=@0x7ffff59fe3d0: 0x7fffe1008f14 "H\277h\260N\367\377\177",
vep=@0x7ffff59fe3d8: 0x7fffe1017620 "\213\004$H\203\304\bPSQRH\213M\330H\205\311\017\204g")
at /home/dai/jdk/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp:344
#5 0x00007ffff6d590ec in TemplateInterpreterGenerator::set_entry_points (
this=0x7ffff59fea10, code=Bytecodes::_ifeq)
at /home/dai/jdk/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp:313
#6 0x00007ffff6d58d4a in TemplateInterpreterGenerator::set_entry_points_for_all_bytes (this=0x7ffff59fea10)
at /home/dai/jdk/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp:269
#7 0x00007ffff6d5893a in TemplateInterpreterGenerator::generate_all (
this=0x7ffff59fea10)
at /home/dai/jdk/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp:227
#8 0x00007ffff6d57259 in TemplateInterpreterGenerator::TemplateInterpreterGenerator (this=0x7ffff59fea10, _code=0x7ffff00febe0)
at /home/dai/jdk/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp:40
#9 0x00007ffff6d55de4 in TemplateInterpreter::initialize_code ()
at /home/dai/jdk/src/hotspot/share/interpreter/templateInterpreter.cpp:62
--Type <RET> for more, q to quit, c to continue without paging--
#10 0x00007ffff65cc48d in interpreter_init_code ()
at /home/dai/jdk/src/hotspot/share/interpreter/interpreter.cpp:137
#11 0x00007ffff65a6d94 in init_globals ()
at /home/dai/jdk/src/hotspot/share/runtime/init.cpp:134
#12 0x00007ffff6d8d1ca in Threads::create_vm (args=0x7ffff59fed50,
canTryAgain=0x7ffff59fec5b)
at /home/dai/jdk/src/hotspot/share/runtime/thread.cpp:2843
#13 0x00007ffff66b243b in JNI_CreateJavaVM_inner (vm=0x7ffff59feda8,
penv=0x7ffff59fedb0, args=0x7ffff59fed50)
at /home/dai/jdk/src/hotspot/share/prims/jni.cpp:3613
#14 0x00007ffff66b2787 in JNI_CreateJavaVM (vm=0x7ffff59feda8,
penv=0x7ffff59fedb0, args=0x7ffff59fed50)
at /home/dai/jdk/src/hotspot/share/prims/jni.cpp:3701
#15 0x00007ffff7faca6a in InitializeJVM (pvm=0x7ffff59feda8,
penv=0x7ffff59fedb0, ifn=0x7ffff59fee00)
at /home/dai/jdk/src/java.base/share/native/libjli/java.c:1459
#16 0x00007ffff7fa95ec in JavaMain (_args=0x7fffffffa9a0)
at /home/dai/jdk/src/java.base/share/native/libjli/java.c:411
#17 0x00007ffff7fb05ec in ThreadJavaMain (args=0x7fffffffa9a0)
at /home/dai/jdk/src/java.base/unix/native/libjli/java_md.c:651
#18 0x00007ffff7c94b43 in start_thread (arg=<optimized out>)
at ./nptl/pthread_create.c:442
#19 0x00007ffff7d26a00 in clone3 ()
--Type <RET> for more, q to quit, c to continue without paging--
at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00007ffff6d73852 in TemplateTable::branch(bool, bool) at /home/dai/jdk/src/hotspot/cpu/x86/templateTable_x86.cpp:2122
breakpoint already hit 1 time
(gdb) p _masm->_code_section->_end

相关阅读

java jdk 为什么一个线程空指针不退出

· 7 min read

背景

了解jdk异常的捕获原理

堆栈

(gdb) bt
#0 PosixSignals::pd_hotspot_signal_handler (sig=sig@entry=11, info=info@entry=0x7ffff7bfd330, uc=uc@entry=0x7ffff7bfd200, thread=0x7ffff00295a0) at /home/ubuntu/jdk/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp:201
#1 0x00007ffff7090f7d in JVM_handle_linux_signal (abort_if_unrecognized=1, ucVoid=0x7ffff7bfd200, info=0x7ffff7bfd330, sig=11) at /home/ubuntu/jdk/src/hotspot/os/posix/signals_posix.cpp:656
#2 JVM_handle_linux_signal (sig=11, info=0x7ffff7bfd330, ucVoid=0x7ffff7bfd200, abort_if_unrecognized=1) at /home/ubuntu/jdk/src/hotspot/os/posix/signals_posix.cpp:557
#3 <signal handler called>
#4 0x00007fffe8537640 in ?? ()
#5 0x0000000000000246 in ?? ()
#6 0x00007fffe8537734 in ?? ()
#7 0x00007ffff79f1858 in ?? () from /home/ubuntu/jdk/build/linux-x86_64-server-fastdebug/jdk/lib/server/libjvm.so
#8 0x00007ffff7bfe290 in ?? ()
#9 0x00007ffff734777a in VM_Version::get_processor_features () at /home/ubuntu/jdk/src/hotspot/cpu/x86/vm_version_x86.cpp:803

这里会返回true , 然后就跳过jdk的退出

bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
ucontext_t* uc, JavaThread* thread) {

/*
NOTE: does not seem to work on linux.
if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) {
// can't decode this kind of signal
info = NULL;
} else {
assert(sig == info->si_signo, "bad siginfo");
}
*/
// decide if this trap can be handled by a stub
address stub = NULL;

address pc = NULL;

//%note os_trap_1
if (info != NULL && uc != NULL && thread != NULL) {
pc = (address) os::Posix::ucontext_get_pc(uc);

if (sig == SIGSEGV && info->si_addr == 0 && info->si_code == SI_KERNEL) {
// An irrecoverable SI_KERNEL SIGSEGV has occurred.
// It's likely caused by dereferencing an address larger than TASK_SIZE.
return false;
}

// Handle ALL stack overflow variations here
if (sig == SIGSEGV) {
address addr = (address) info->si_addr;

// check if fault address is within thread stack
if (thread->is_in_full_stack(addr)) {
// stack overflow
if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) {
return true; // continue
}
}
}

if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) {
// Verify that OS save/restore AVX registers.
stub = VM_Version::cpuinfo_cont_addr();
}

if (thread->thread_state() == _thread_in_Java) {
// Java thread running in Java code => find exception handler if any
// a fault inside compiled code, the interpreter, or a stub

if (sig == SIGSEGV && SafepointMechanism::is_poll_address((address)info->si_addr)) {
stub = SharedRuntime::get_poll_stub(pc);
} else if (sig == SIGBUS /* && info->si_code == BUS_OBJERR */) {
// BugId 4454115: A read from a MappedByteBuffer can fault
// here if the underlying file has been truncated.
// Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob(pc);
CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
bool is_unsafe_arraycopy = thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc);
if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) {
address next_pc = Assembler::locate_next_instruction(pc);
if (is_unsafe_arraycopy) {
next_pc = UnsafeCopyMemory::page_error_continue_pc(pc);
}
stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
}
}
else

#ifdef AMD64
if (sig == SIGFPE &&
(info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)) {
stub =
SharedRuntime::
continuation_for_implicit_exception(thread,
pc,
SharedRuntime::
IMPLICIT_DIVIDE_BY_ZERO);
#else
if (sig == SIGFPE /* && info->si_code == FPE_INTDIV */) {
// HACK: si_code does not work on linux 2.2.12-20!!!
int op = pc[0];
if (op == 0xDB) {
// FIST
// TODO: The encoding of D2I in x86_32.ad can cause an exception
// prior to the fist instruction if there was an invalid operation
// pending. We want to dismiss that exception. From the win_32
// side it also seems that if it really was the fist causing
// the exception that we do the d2i by hand with different
// rounding. Seems kind of weird.
// NOTE: that we take the exception at the NEXT floating point instruction.
assert(pc[0] == 0xDB, "not a FIST opcode");
assert(pc[1] == 0x14, "not a FIST opcode");
assert(pc[2] == 0x24, "not a FIST opcode");
return true;
} else if (op == 0xF7) {
// IDIV
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
} else {
// TODO: handle more cases if we are using other x86 instructions
// that can generate SIGFPE signal on linux.
tty->print_cr("unknown opcode 0x%X with SIGFPE.", op);
fatal("please update this code.");
}
#endif // AMD64
} else if (sig == SIGSEGV &&
MacroAssembler::uses_implicit_null_check(info->si_addr)) {
// Determination of interpreter/vtable stub/compiled code null exception
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
}
} else if ((thread->thread_state() == _thread_in_vm ||
thread->thread_state() == _thread_in_native) &&
(sig == SIGBUS && /* info->si_code == BUS_OBJERR && */
thread->doing_unsafe_access())) {
address next_pc = Assembler::locate_next_instruction(pc);
if (UnsafeCopyMemory::contains_pc(pc)) {
next_pc = UnsafeCopyMemory::page_error_continue_pc(pc);
}
stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
}

// jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in
// and the heap gets shrunk before the field access.
if ((sig == SIGSEGV) || (sig == SIGBUS)) {
address addr = JNI_FastGetField::find_slowcase_pc(pc);
if (addr != (address)-1) {
stub = addr;
}
}
}

#ifndef AMD64
// Execution protection violation
//
// This should be kept as the last step in the triage. We don't
// have a dedicated trap number for a no-execute fault, so be
// conservative and allow other handlers the first shot.
//
// Note: We don't test that info->si_code == SEGV_ACCERR here.
// this si_code is so generic that it is almost meaningless; and
// the si_code for this condition may change in the future.
// Furthermore, a false-positive should be harmless.
if (UnguardOnExecutionViolation > 0 &&
stub == NULL &&
(sig == SIGSEGV || sig == SIGBUS) &&
uc->uc_mcontext.gregs[REG_TRAPNO] == trap_page_fault) {
int page_size = os::vm_page_size();
address addr = (address) info->si_addr;
address pc = os::Posix::ucontext_get_pc(uc);
// Make sure the pc and the faulting address are sane.
//
// If an instruction spans a page boundary, and the page containing
// the beginning of the instruction is executable but the following
// page is not, the pc and the faulting address might be slightly
// different - we still want to unguard the 2nd page in this case.
//
// 15 bytes seems to be a (very) safe value for max instruction size.
bool pc_is_near_addr =
(pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15);
bool instr_spans_page_boundary =
(align_down((intptr_t) pc ^ (intptr_t) addr,
(intptr_t) page_size) > 0);

if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) {
static volatile address last_addr =
(address) os::non_memory_address_word();

// In conservative mode, don't unguard unless the address is in the VM
if (addr != last_addr &&
(UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) {

// Set memory to RWX and retry
address page_start = align_down(addr, page_size);
bool res = os::protect_memory((char*) page_start, page_size,
os::MEM_PROT_RWX);

log_debug(os)("Execution protection violation "
"at " INTPTR_FORMAT
", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr),
p2i(page_start), (res ? "success" : "failed"), errno);
stub = pc;

// Set last_addr so if we fault again at the same address, we don't end
// up in an endless loop.
//
// There are two potential complications here. Two threads trapping at
// the same address at the same time could cause one of the threads to
// think it already unguarded, and abort the VM. Likely very rare.
//
// The other race involves two threads alternately trapping at
// different addresses and failing to unguard the page, resulting in
// an endless loop. This condition is probably even more unlikely than
// the first.
//
// Although both cases could be avoided by using locks or thread local
// last_addr, these solutions are unnecessary complication: this
// handler is a best-effort safety net, not a complete solution. It is
// disabled by default and should only be used as a workaround in case
// we missed any no-execute-unsafe VM code.

last_addr = addr;
}
}
}
#endif // !AMD64

if (stub != NULL) {
// save all thread context in case we need to restore it
if (thread != NULL) thread->set_saved_exception_pc(pc);

os::Posix::ucontext_set_pc(uc, stub);
return true; ///////////////////////////////////////// 这里会是true
}

return false;
}

相关阅读

java unbox

· 2 min read

背景

想比较两个数字的时候:Long的equal比较的值,而不是对象的地址

    public boolean equals(Object obj) {
if (obj instanceof Long) {
return this.value == (Long)obj;
} else {
return false;
}
}

为什么?

因为涉及到binary numeric promotion

jls 文档

相关文档

// "==" 操作符 的jls 文档

15.21.1 Numerical Equality Operators == and !=
If the operands of an equality operator are both of numeric type, or one is of
numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric
promotion is performed on the operands (§5.6.2).
// Binary Numeric Promotion 文档

5.6.2 Binary Numeric Promotion
When an operator applies binary numeric promotion to a pair of operands, each
of which must denote a value that is convertible to a numeric type, the following
rules apply, in order:
1. If any operand is of a reference type, it is subjected to unboxing conversion
// == 会触发 Binary Numeric Promotion
Binary numeric promotion is performed on the operands of certain operators:
• The multiplicative operators *, /, and % (§15.17)
• The addition and subtraction operators for numeric types + and - (§15.18.2)
• The numerical comparison operators <, <=, >, and >= (§15.20.1)
• The numerical equality operators == and != (§15.21.1)

所以

    @Test
public void testEq(){
Long i = new Long(1000L);
Long j = new Long(1000L);
Assert.assertFalse(i == j); // 两个都是对象 , 不满足Binary Numeric Promotion 条件 ,所以不会拆箱 , 所以比较的是地址

Assert.assertTrue(i == 1000L); // 这里 满足 Binary Numeric Promotion 条件 , 所以比较的是值
}

java main

· 10 min read

main 函数介绍

java的main函数在入口函数 一般都是这个签名

public static void main(String[] argv){

}

那么这个main函数是怎么加载的呢?

调用时机:

jni_invoke_static

(gdb) p method._value->print()
{method}
- this oop: 0x00007fffb44112d8
- method holder: 'Hello'
- constants: 0x00007fffb4411030 constant pool [34] {0x00007fffb4411030} for 'Hello' cache=0x00007fffb44113e0
- access: 0x9 public static
- name: 'main'
- signature: '([Ljava/lang/String;)V'
- max stack: 3
- max locals: 1
- size of params: 1
- method size: 13
- vtable index: -2
- i2i entry: 0x00007fffe100dc00 /////////// entity_point
- adapters: AHE@0x00007ffff01015d0: 0xb i2c: 0x00007fffe1114d60 c2i: 0x00007fffe1114e1a c2iUV: 0x00007fffe1114de4 c2iNCI: 0x00007fffe1114e57
- compiled entry 0x00007fffe1114e1a
- code size: 13
- code start: 0x00007fffb44112c0 // 这里是bytecode 的起点
- code end (excl): 0x00007fffb44112cd // 这是bytecode的终点
- checked ex length: 0
- linenumber start: 0x00007fffb44112cd
- localvar length: 0
$7 = void

(gdb) info registers 
rax 0x7ffff59fe940 140737314285888
rbx 0x7fffe1000c9e 140736968264862
rcx 0x7fffb44112d8 140736217551576
rdx 0xa 10
rsi 0x7ffff59febf8 140737314286584
rdi 0x7ffff59fe940 140737314285888
rbp 0x7ffff59fe870 0x7ffff59fe870
rsp 0x7ffff59fe810 0x7ffff59fe810
r8 0x7fffe100dc00 140736968317952 // 这里就是入口点
r9 0x7ffff59feaf0 140737314286320
r10 0x7ffff053ae20 140737225403936
r11 0x7ffff0000090 140737219920016
r12 0x1 1
r13 0x0 0
r14 0x7ffff7c94850 140737350551632
r15 0x7fffffffa800 140737488332800
rip 0x7fffe1000ca6 0x7fffe1000ca6
eflags 0x202 [ IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
$2 = void
(gdb) where
#0 JavaCalls::call_helper (result=0x7ffff7bfec10, method=..., args=0x7ffff7bfeb30, __the_thread__=0x7ffff00295a0) at /home/ubuntu/jdk/src/hotspot/share/runtime/javaCalls.cpp:333
#1 0x00007ffff6799785 in jni_invoke_static (result=result@entry=0x7ffff7bfec10, method_id=method_id@entry=0x7ffff02c84d0, args=args@entry=0x7ffff7bfec80, __the_thread__=__the_thread__@entry=0x7ffff00295a0, env=0x7ffff00298d0,
call_type=JNI_STATIC, receiver=0x0) at /home/ubuntu/jdk/src/hotspot/share/prims/jni.cpp:889
#2 0x00007ffff679cd19 in jni_CallStaticVoidMethod (env=0x7ffff00298d0, cls=<optimized out>, methodID=0x7ffff02c84d0) at /home/ubuntu/jdk/src/hotspot/share/prims/jni.cpp:1713
#3 0x00007ffff7fadcb5 in JavaMain (_args=<optimized out>) at /home/ubuntu/jdk/src/java.base/share/native/libjli/java.c:547
#4 0x00007ffff7fb0f4d in ThreadJavaMain (args=<optimized out>) at /home/ubuntu/jdk/src/java.base/unix/native/libjli/java_md.c:651
#5 0x00007ffff7c94b43 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#6 0x00007ffff7d26a00 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
(gdb

c++ 调用java static method方法

调用generate_call_stub ,这是入口点,这个会调用method的entry_point

address StubGenerator::generate_call_stub(address& return_address) {

assert((int)frame::entry_frame_after_call_words == -(int)rsp_after_call_off + 1 &&
(int)frame::entry_frame_call_wrapper_offset == (int)call_wrapper_off,
"adjust this code");
StubCodeMark mark(this, "StubRoutines", "call_stub");
address start = __ pc();

// same as in generate_catch_exception()!
const Address rsp_after_call(rbp, rsp_after_call_off * wordSize);

const Address call_wrapper (rbp, call_wrapper_off * wordSize);
const Address result (rbp, result_off * wordSize);
const Address result_type (rbp, result_type_off * wordSize);
const Address method (rbp, method_off * wordSize);
const Address entry_point (rbp, entry_point_off * wordSize);
const Address parameters (rbp, parameters_off * wordSize);
const Address parameter_size(rbp, parameter_size_off * wordSize);

// same as in generate_catch_exception()!
const Address thread (rbp, thread_off * wordSize);

const Address r15_save(rbp, r15_off * wordSize);
const Address r14_save(rbp, r14_off * wordSize);
const Address r13_save(rbp, r13_off * wordSize);
const Address r12_save(rbp, r12_off * wordSize);
const Address rbx_save(rbp, rbx_off * wordSize);

// stub code
__ enter();
__ subptr(rsp, -rsp_after_call_off * wordSize);

// save register parameters
#ifndef _WIN64
__ movptr(parameters, c_rarg5); // parameters
__ movptr(entry_point, c_rarg4); // entry_point
#endif

__ movptr(method, c_rarg3); // method
__ movl(result_type, c_rarg2); // result type
__ movptr(result, c_rarg1); // result
__ movptr(call_wrapper, c_rarg0); // call wrapper

// save regs belonging to calling function
__ movptr(rbx_save, rbx);
__ movptr(r12_save, r12);
__ movptr(r13_save, r13);
__ movptr(r14_save, r14);
__ movptr(r15_save, r15);

#ifdef _WIN64
int last_reg = 15;
if (UseAVX > 2) {
last_reg = 31;
}
if (VM_Version::supports_evex()) {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ vextractf32x4(xmm_save(i), as_XMMRegister(i), 0);
}
} else {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ movdqu(xmm_save(i), as_XMMRegister(i));
}
}

const Address rdi_save(rbp, rdi_off * wordSize);
const Address rsi_save(rbp, rsi_off * wordSize);

__ movptr(rsi_save, rsi);
__ movptr(rdi_save, rdi);
#else
const Address mxcsr_save(rbp, mxcsr_off * wordSize);
{
Label skip_ldmx;
__ stmxcsr(mxcsr_save);
__ movl(rax, mxcsr_save);
__ andl(rax, 0xFFC0); // Mask out any pending exceptions (only check control and mask bits)
ExternalAddress mxcsr_std(StubRoutines::x86::addr_mxcsr_std());
__ cmp32(rax, mxcsr_std, rscratch1);
__ jcc(Assembler::equal, skip_ldmx);
__ ldmxcsr(mxcsr_std, rscratch1);
__ bind(skip_ldmx);
}
#endif

// Load up thread register
__ movptr(r15_thread, thread);
__ reinit_heapbase();

#ifdef ASSERT
// make sure we have no pending exceptions
{
Label L;
__ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD);
__ jcc(Assembler::equal, L);
__ stop("StubRoutines::call_stub: entered with pending exception");
__ bind(L);
}
#endif

// pass parameters if any
BLOCK_COMMENT("pass parameters if any");
Label parameters_done;
__ movl(c_rarg3, parameter_size);
__ testl(c_rarg3, c_rarg3);
__ jcc(Assembler::zero, parameters_done);

Label loop;
__ movptr(c_rarg2, parameters); // parameter pointer
__ movl(c_rarg1, c_rarg3); // parameter counter is in c_rarg1
__ BIND(loop);
__ movptr(rax, Address(c_rarg2, 0));// get parameter
__ addptr(c_rarg2, wordSize); // advance to next parameter
__ decrementl(c_rarg1); // decrement counter
__ push(rax); // pass parameter
__ jcc(Assembler::notZero, loop);

// call Java function
__ BIND(parameters_done);
__ movptr(rbx, method); // get Method*
__ movptr(c_rarg1, entry_point); // get entry_point
__ mov(r13, rsp); // set sender sp
BLOCK_COMMENT("call Java function");
__ call(c_rarg1);

BLOCK_COMMENT("call_stub_return_address:");
return_address = __ pc();

// store result depending on type (everything that is not
// T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT)
__ movptr(c_rarg0, result);
Label is_long, is_float, is_double, exit;
__ movl(c_rarg1, result_type);
__ cmpl(c_rarg1, T_OBJECT);
__ jcc(Assembler::equal, is_long);
__ cmpl(c_rarg1, T_LONG);
__ jcc(Assembler::equal, is_long);
__ cmpl(c_rarg1, T_FLOAT);
__ jcc(Assembler::equal, is_float);
__ cmpl(c_rarg1, T_DOUBLE);
__ jcc(Assembler::equal, is_double);

// handle T_INT case
__ movl(Address(c_rarg0, 0), rax);

__ BIND(exit);

// pop parameters
__ lea(rsp, rsp_after_call);

#ifdef ASSERT
// verify that threads correspond
{
Label L1, L2, L3;
__ cmpptr(r15_thread, thread);
__ jcc(Assembler::equal, L1);
__ stop("StubRoutines::call_stub: r15_thread is corrupted");
__ bind(L1);
__ get_thread(rbx);
__ cmpptr(r15_thread, thread);
__ jcc(Assembler::equal, L2);
__ stop("StubRoutines::call_stub: r15_thread is modified by call");
__ bind(L2);
__ cmpptr(r15_thread, rbx);
__ jcc(Assembler::equal, L3);
__ stop("StubRoutines::call_stub: threads must correspond");
__ bind(L3);
}
#endif

__ pop_cont_fastpath();

// restore regs belonging to calling function
#ifdef _WIN64
// emit the restores for xmm regs
if (VM_Version::supports_evex()) {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ vinsertf32x4(as_XMMRegister(i), as_XMMRegister(i), xmm_save(i), 0);
}
} else {
for (int i = xmm_save_first; i <= last_reg; i++) {
__ movdqu(as_XMMRegister(i), xmm_save(i));
}
}
#endif
__ movptr(r15, r15_save);
__ movptr(r14, r14_save);
__ movptr(r13, r13_save);
__ movptr(r12, r12_save);
__ movptr(rbx, rbx_save);

#ifdef _WIN64
__ movptr(rdi, rdi_save);
__ movptr(rsi, rsi_save);
#else
__ ldmxcsr(mxcsr_save);
#endif

// restore rsp
__ addptr(rsp, -rsp_after_call_off * wordSize);

// return
__ vzeroupper();
__ pop(rbp);
__ ret(0);

// handle return types different from T_INT
__ BIND(is_long);
__ movq(Address(c_rarg0, 0), rax);
__ jmp(exit);

__ BIND(is_float);
__ movflt(Address(c_rarg0, 0), xmm0);
__ jmp(exit);

__ BIND(is_double);
__ movdbl(Address(c_rarg0, 0), xmm0);
__ jmp(exit);

return start;
}

如何列出汇编代码

// 列出从0x7fffe1000ca6 开始的100 个汇编指令
x/100i 0x7fffe1000ca6

如何用gdb断点地址

(gdb) b *0x7fffe1000ca6

方法入口点

JavaCalls::call_helper
-----> address entry_point = method->from_interpreted_entry();
---------> Atomic::load_acquire(&_from_interpreted_entry)

执行方法的时候会调用 _from_interpreted_entry生成对应的栈以及上下文,其中寄存器r13会指向下一个bytecode , 然后通过r13读取下一个bytecode的例程,并执行对应例程

那么_from_interpreted_entry 是从哪里可以设置的? 在link_method会设置

void Method::link_method(const methodHandle& h_method, TRAPS) {
...
address entry = Interpreter::entry_for_method(h_method);
set_interpreter_entry(entry);
...
}

这里的Interpreter::entry_for_method(h_method)是下面这个数组:

AbstractInterpreter::_entry_table  

那么_entry_table是在哪里设置呢?

在下面

void TemplateInterpreterGenerator::generate_all(){

#define method_entry(kind) \
{ CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \
Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \
}

// all non-native method kinds
method_entry(zerolocals) // 就是这里会设置AbstractInterpreter::_entry_table[Interpreter::zerolocals] = generate_method_entry(Interpreter::zerolocals)
}

这里生成的例程就是包括方法帧

address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
// determine code generation flags
bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods;

// ebx: Method*
// rbcp: sender sp
address entry_point = __ pc();

const Address constMethod(rbx, Method::const_offset());
const Address access_flags(rbx, Method::access_flags_offset());
const Address size_of_parameters(rdx,
ConstMethod::size_of_parameters_offset());
const Address size_of_locals(rdx, ConstMethod::size_of_locals_offset());


// get parameter size (always needed)
__ movptr(rdx, constMethod);
__ load_unsigned_short(rcx, size_of_parameters);

// rbx: Method*
// rcx: size of parameters
// rbcp: sender_sp (could differ from sp+wordSize if we were called via c2i )

__ load_unsigned_short(rdx, size_of_locals); // get size of locals in words
__ subl(rdx, rcx); // rdx = no. of additional locals

// YYY
// __ incrementl(rdx);
// __ andl(rdx, -2);

// see if we've got enough room on the stack for locals plus overhead.
generate_stack_overflow_check();

// get return address
__ pop(rax);

// compute beginning of parameters
__ lea(rlocals, Address(rsp, rcx, Interpreter::stackElementScale(), -wordSize));

// rdx - # of additional locals
// allocate space for locals
// explicitly initialize locals
{
Label exit, loop;
__ testl(rdx, rdx);
__ jcc(Assembler::lessEqual, exit); // do nothing if rdx <= 0
__ bind(loop);
__ push((int) NULL_WORD); // initialize local variables
__ decrementl(rdx); // until everything initialized
__ jcc(Assembler::greater, loop);
__ bind(exit);
}

// initialize fixed part of activation frame
generate_fixed_frame(false);

// make sure method is not native & not abstract
#ifdef ASSERT
__ movl(rax, access_flags);
{
Label L;
__ testl(rax, JVM_ACC_NATIVE);
__ jcc(Assembler::zero, L);
__ stop("tried to execute native method as non-native");
__ bind(L);
}
{
Label L;
__ testl(rax, JVM_ACC_ABSTRACT);
__ jcc(Assembler::zero, L);
__ stop("tried to execute abstract method in interpreter");
__ bind(L);
}
#endif

// Since at this point in the method invocation the exception
// handler would try to exit the monitor of synchronized methods
// which hasn't been entered yet, we set the thread local variable
// _do_not_unlock_if_synchronized to true. The remove_activation
// will check this flag.

const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);
NOT_LP64(__ get_thread(thread));
const Address do_not_unlock_if_synchronized(thread,
in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
__ movbool(do_not_unlock_if_synchronized, true);

__ profile_parameters_type(rax, rcx, rdx);
// increment invocation count & check for overflow
Label invocation_counter_overflow;
if (inc_counter) {
generate_counter_incr(&invocation_counter_overflow);
}

Label continue_after_compile;
__ bind(continue_after_compile);

// check for synchronized interpreted methods
bang_stack_shadow_pages(false);

// reset the _do_not_unlock_if_synchronized flag
NOT_LP64(__ get_thread(thread));
__ movbool(do_not_unlock_if_synchronized, false);

// check for synchronized methods
// Must happen AFTER invocation_counter check and stack overflow check,
// so method is not locked if overflows.
if (synchronized) {
// Allocate monitor and lock method
lock_method();
} else {
// no synchronization necessary
#ifdef ASSERT
{
Label L;
__ movl(rax, access_flags);
__ testl(rax, JVM_ACC_SYNCHRONIZED);
__ jcc(Assembler::zero, L);
__ stop("method needs synchronization");
__ bind(L);
}
#endif
}

// start execution
#ifdef ASSERT
{
Label L;
const Address monitor_block_top (rbp,
frame::interpreter_frame_monitor_block_top_offset * wordSize);
__ movptr(rax, monitor_block_top);
__ cmpptr(rax, rsp);
__ jcc(Assembler::equal, L);
__ stop("broken stack frame setup in interpreter");
__ bind(L);
}
#endif

// jvmti support
__ notify_method_entry();

__ dispatch_next(vtos); //////// 生成方法帧和上下文执行 , 执行下一个bytecode

// invocation counter overflow
if (inc_counter) {
// Handle overflow of counter and compile method
__ bind(invocation_counter_overflow);
generate_counter_overflow(continue_after_compile);
}

return entry_point;
}

相关阅读

WARNING: An illegal reflective access operation has occurred groovy

· One min read

背景

jdk11 的时候,会抛出如下的报错:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedClass (file:/D:/packageFile/org/codehaus/groovy/groovy/2.5.14/groovy-2.5.14.jar) to method java.lang.Object.finalize()
WARNING: Please consider reporting this to the maintainers of org.codehaus.groovy.reflection.CachedClass
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release