前言

09 给对象添加偏向锁的调试 , 接着文章 继续调试偏向锁, 我们这里要调试的场景是 偏向锁退出的场景 

 

一下内容基于 jdk9 + lldb-1001.0.13.3 

另外一下 运行时数据可能是来自于多次调试, 可能会存在运行时数据 对不上的情况, 但是的条理逻辑会在文字中描述清楚的 

 

 

偏向锁退出测试用例

package com.hx.test04;/*** SynchronizedObject** @author Jerry.X.He <970655147@qq.com>* @version 1.0* @date 2020-04-03 15:14*/
public class Test26SynchronizeObject implements Cloneable {// identStrprivate String identStr = "xyz";int f01;int f02;int f03;int f04;int f05;// Test25SynchronizeObjectpublic static void main(String[] args) throws Exception {Test26SynchronizeObject lockObj = new Test26SynchronizeObject();synchronized (lockObj) {//      Test26SynchronizeObject cloned = (Test26SynchronizeObject) lockObj.clone();
//      System.out.println(lockObj.identStr);}}}

 

对应的字节码信息如下, 下面参照可能需要使用到 

master:classes jerry$ javap -c com/hx/test04/Test26SynchronizeObject.class 
Compiled from "Test26SynchronizeObject.java"
public class com.hx.test04.Test26SynchronizeObject implements java.lang.Cloneable {int f01;int f02;int f03;int f04;int f05;public com.hx.test04.Test26SynchronizeObject();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: aload_05: ldc           #2                  // String xyz7: putfield      #3                  // Field identStr:Ljava/lang/String;10: returnpublic static void main(java.lang.String[]) throws java.lang.Exception;Code:0: new           #4                  // class com/hx/test04/Test26SynchronizeObject3: dup4: invokespecial #5                  // Method "<init>":()V7: astore_18: aload_19: dup10: astore_211: monitorenter12: aload_213: monitorexit14: goto          2217: astore_318: aload_219: monitorexit20: aload_321: athrow22: returnException table:from    to  target type12    14    17   any17    20    17   any
}

 

 

进入lldb的调试

进入lldb 之后如下, 省略了一部分输出, 不过应该能够看出 当前端点是停在了 javaCalls.cpp -l 410 这里 

Process 2543 resuming
Process 2543 stopped
* thread #5, stop reason = breakpoint 1.1frame #0: 0x0000000103923592 libjvm.dylib`::jni_CallStaticVoidMethod(env=0x0000000101005a28, cls=0x00000001001061d0, methodID=0x0000000104905990) at jni.cpp:1989:211986	  va_start(args, methodID);1987	  JavaValue jvalue(T_VOID);1988	  JNI_ArgumentPusherVaArg ap(methodID, args);
-> 1989	  jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK);1990	  va_end(args);1991	JNI_END1992	
Target 0: (java) stopped.(lldb) br set -f javaCalls.cpp -l 410
Breakpoint 2: where = libjvm.dylib`JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, Thread*) + 1496 at javaCalls.cpp:410:7, address = 0x00000001038eba68
(lldb) c
Process 2543 resuming
Process 2543 stopped
* thread #5, stop reason = breakpoint 2.1frame #0: 0x00000001038eba68 libjvm.dylib`JavaCalls::call_helper(result=0x0000700004af3d48, method=0x0000700004af3a48, args=0x0000700004af3a90, __the_thread__=0x0000000101005800) at javaCalls.cpp:410:7407 	  { JavaCallWrapper link(method, receiver, result, CHECK);408 	    { HandleMark hm(thread);  // HandleMark used by HandleMarkCleaner409 	
-> 410 	      StubRoutines::call_stub()(411 	        (address)&link,412 	        // (intptr_t*)&(result->_value), // see NOTE above (compiler problem)413 	        result_val_address,          // see NOTE above (compiler problem)
Target 0: (java) stopped.(lldb) p _active_table._table[9][194]
(address) $0 = 0x000000010584f980 "XH;"

 

定位一下当前方法, 当前这里正是在调用 main 方法 

(lldb) p method()->print()
{method}- this oop:          0x000000011d36ffd8- method holder:     'com/hx/test04/Test26SynchronizeObject'- constants:         0x000000011d36fc68 constant pool [45] {0x000000011d36fc68} for 'com/hx/test04/Test26SynchronizeObject' cache=0x000000011d370050- access:            0x20000009  public static - name:              'main'- signature:         '([Ljava/lang/String;)V'- max stack:         3- max locals:        4- size of params:    1- method size:       11- vtable index:      -2- i2i entry:         0x000000010582a700- adapters:          AHE@0x00000001018770e0: 0xb0000000 i2c: 0x00000001059a4460 c2i: 0x00000001059a459a c2iUV: 0x00000001059a456d- compiled entry     0x00000001059a459a- code size:         23- code start:        0x000000011d36ff88- code end (excl):   0x000000011d36ff9f- checked ex length: 1- checked ex start:  0x000000011d36ffd4- linenumber start:  0x000000011d36ff9f- localvar length:   2- localvar start:    0x000000011d36ffa8

 

接着在 monitor_exit 的地方打上一个断点 

(lldb) p _active_table._table[9][195]
(address) $1 = 0x000000010504fde0 "XH;"
(lldb) b 0x000000010504fde1
Breakpoint 3: address = 0x000000010504fde1
(lldb) c
Process 2555 resuming
Process 2555 stopped
* thread #5, stop reason = breakpoint 3.1frame #0: 0x000000010504fde1
->  0x10504fde1: cmpq   (%rax), %rax0x10504fde4: movq   -0x48(%rbp), %rsi0x10504fde8: leaq   -0x48(%rbp), %rdx0x10504fdec: jmp    0x10504fdfc
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:rax = 0x0000000747bb8748rbx = 0x00000000000000c3rcx = 0x0000000747bb8748rdx = 0x0000700003d92638rdi = 0x0000000104801800rsi = 0x0000700003d92628rbp = 0x0000700003d92680rsp = 0x0000700003d92628r8 = 0x0000000000000000r9 = 0x0000000000000020r10 = 0x0000000103b0aa70  libjvm.dylib`TemplateInterpreter::_active_table + 16384r11 = 0x00006ffeff58fe00r12 = 0x0000000000000000r13 = 0x000000011c96ff95r14 = 0x0000700003d926a8r15 = 0x0000000104801800rip = 0x000000010504fde1rflags = 0x0000000000000206cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) x 0x000000011c96ff95
0x11c96ff95: c3 a7 00 08 4e 2c c3 2d bf b1 ff 00 2e 42 25 52  ç..N,?-???..B%R
0x11c96ffa5: 00 00 00 00 00 17 00 19 00 1a 00 00 00 00 00 08  ................
(lldb) p ((oopDesc*)0x0000000747bb8748)->print()
com.hx.test04.Test26SynchronizeObject 
{0x0000000747bb8748} - klass: 'com/hx/test04/Test26SynchronizeObject'- ---- fields (total size 5 words):- 'f01' 'I' @12  0- 'f02' 'I' @16  0- 'f03' 'I' @20  0- 'f04' 'I' @24  0- 'f05' 'I' @28  0- private 'identStr' 'Ljava/lang/String;' @32  "xyz"{0x0000000747bb8770} (e8f770ee 0)
(lldb) p ((oopDesc*)0x0000000747bb8748)->mark()->biased_locker()->threadObj()->print()
java.lang.Thread 
{0x0000000747f069d8} - klass: 'java/lang/Thread'- ---- fields (total size 47 words):- private 'priority' 'I' @12  5- private 'eetop' 'J' @16  4370470912 (4801800 1)- private 'stackSize' 'J' @24  0 (0 0)- private 'nativeParkEventPointer' 'J' @32  0 (0 0)- private 'tid' 'J' @40  1 (1 0)- private volatile 'threadStatus' 'I' @48  5- private 'single_step' 'Z' @52  false- private 'daemon' 'Z' @53  false- private 'stillborn' 'Z' @54  false- private volatile 'name' 'Ljava/lang/String;' @56  "main"{0x0000000747f06b50} (e8fe0d6a 0)- private 'threadQ' 'Ljava/lang/Thread;' @60  NULL (0 0)- private 'target' 'Ljava/lang/Runnable;' @64  NULL (0 e8fe0c85)- private 'group' 'Ljava/lang/ThreadGroup;' @68  a 'java/lang/ThreadGroup'{0x0000000747f06428} (e8fe0c85 e8fc0af7)- private 'contextClassLoader' 'Ljava/lang/ClassLoader;' @72  a 'jdk/internal/loader/ClassLoaders$AppClassLoader'{0x0000000747e057b8} (e8fc0af7 e8fe0d91)- private 'inheritedAccessControlContext' 'Ljava/security/AccessControlContext;' @76  a 'java/security/AccessControlContext'{0x0000000747f06c88} (e8fe0d91 e8fe2fb8)- 'threadLocals' 'Ljava/lang/ThreadLocal$ThreadLocalMap;' @80  a 'java/lang/ThreadLocal$ThreadLocalMap'{0x0000000747f17dc0} (e8fe2fb8 0)- 'inheritableThreadLocals' 'Ljava/lang/ThreadLocal$ThreadLocalMap;' @84  NULL (0 0)- volatile 'parkBlocker' 'Ljava/lang/Object;' @88  NULL (0 0)- private volatile 'blocker' 'Lsun/nio/ch/Interruptible;' @92  NULL (0 e8fe0d70)- private final 'blockerLock' 'Ljava/lang/Object;' @96  a 'java/lang/Object'{0x0000000747f06b80} (e8fe0d70 0)- private volatile 'uncaughtExceptionHandler' 'Ljava/lang/Thread$UncaughtExceptionHandler;' @100  NULL (0 0)- 'threadLocalRandomSeed' 'J' @232  0 (0 0)- 'threadLocalRandomProbe' 'I' @240  0- 'threadLocalRandomSecondarySeed' 'I' @244  0

0xc3 表示 monitorenter, 0xa7 表示 goto, 0x4e 表示 astore_3 

结合上面的字节码 很容易定位到当前是在执行 monitorexit 
并且 lockObj 上面已经添加了 偏向锁 

ax 存储的是对象 lockObj 

 

查看一下 栈帧中的信息, 之所以要贴一下 栈帧信息, 是因为 monitorexit 里面的处理需要处理 栈帧中的一部分数据 

(lldb) re r
General Purpose Registers:rax = 0x0000000747bb8748rbx = 0x00000000000000c3rcx = 0x0000000747bb8748rdx = 0x0000700003d92638rdi = 0x0000000104801800rsi = 0x0000700003d92628rbp = 0x0000700003d92680rsp = 0x0000700003d92628r8 = 0x0000000000000000r9 = 0x0000000000000020r10 = 0x0000000103b0aa70  libjvm.dylib`TemplateInterpreter::_active_table + 16384r11 = 0x00006ffeff58fe00r12 = 0x0000000000000000r13 = 0x000000011c96ff95r14 = 0x0000700003d926a8r15 = 0x0000000104801800rip = 0x000000010504fde1rflags = 0x0000000000000206cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) x 0x0000700003d92628 -c 0x100
0x700003d92628: 48 87 bb 47 07 00 00 00 48 87 bb 47 07 00 00 00  H.?G....H.?G....
0x700003d92638: 28 26 d9 03 00 70 00 00 94 ff 96 1c 01 00 00 00  (&?..p...?......
0x700003d92648: a8 26 d9 03 00 70 00 00 50 00 97 1c 01 00 00 00  ?&?..p..P.......
0x700003d92658: 00 00 00 00 00 00 00 00 28 82 bb 47 07 00 00 00  ........(.?G....
0x700003d92668: d8 ff 96 1c 01 00 00 00 00 00 00 00 00 00 00 00  ??..............
0x700003d92678: a8 26 d9 03 00 70 00 00 10 27 d9 03 00 70 00 00  ?&?..p...'?..p..
0x700003d92688: f1 09 00 05 01 00 00 00 00 00 00 00 00 00 00 00  ?...............
0x700003d92698: 48 87 bb 47 07 00 00 00 48 87 bb 47 07 00 00 00  H.?G....H.?G....
0x700003d926a8: 38 87 bb 47 07 00 00 00 a0 1f 00 00 03 00 00 00  8.?G....?.......
0x700003d926b8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x700003d926c8: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0x700003d926d8: 00 30 d9 03 00 70 00 00 20 28 d9 03 00 70 00 00  .0?..p.. (?..p..
0x700003d926e8: 50 2d d9 03 00 70 00 00 0a 00 00 00 00 70 00 00  P-?..p.......p..
0x700003d926f8: d8 ff 96 1c 01 00 00 00 00 a7 02 05 01 00 00 00  ??.......?......
0x700003d92708: a0 2a d9 03 00 70 00 00 e0 28 d9 03 00 70 00 00  ?*?..p..?(?..p..
0x700003d92718: 1d bb 0e 03 01 00 00 00 01 00 00 00 00 70 00 00  .?...........p..0x700003d92628 : 0x0000000747bb8748 : BasicLockObject.lock
0x700003d92630 : 0x0000000747bb8748 : BasicLockObject.obj
0x700003d92638 : 0x700003d92628 : expression bottom
0x700003d92640 : 0x00011c96ff94 : byte code pointer
0x700003d92648 : 0x700003d926a8 : pointer to locals
0x700003d92650 : 0x00011c970050 : constants pool cache
0x700003d92658 : 0x000000000000 : method data oop
0x700003d92660 : 0x0747bb8228 : java mirror
0x700003d92668 : 0x011c96ffd8 : method oop
0x700003d92670 : 0x000000000000 : last java stack pointer
0x700003d92678 : 0x700003d926a8 : old stack pointer
0x700003d92680 : 0x700003d92710 : old frame pointer
0x700003d92688 : 0x01050009f1 : return address[entry_point's address]
0x700003d92690 : 0x000000000000 : ex if exists
0x700003d92698 : 0x0000000747bb8748 : lockObj for monitor enter/exit
0x700003d926a0 : 0x0000000747bb8748 : lockObj
0x700003d926a8 : 0x0000000747bb8738 : args
0x700003d926b0 : 0x0300001fa0 : $mxcsr

 

 

查询BasicObjectLock

对应 monitorexit 的汇编的模板代码如下 

templateTable_x86.cpp monitorexit 

void TemplateTable::monitorexit() {transition(atos, vtos);// check for NULL object__ null_check(rax);const Address monitor_block_top(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);const Address monitor_block_bot(rbp, frame::interpreter_frame_initial_sp_offset * wordSize);const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;Register rtop = LP64_ONLY(c_rarg1) NOT_LP64(rdx);Register rbot = LP64_ONLY(c_rarg2) NOT_LP64(rbx);Label found;// find matching slot{Label entry, loop;__ movptr(rtop, monitor_block_top); // points to current entry,// starting with top-most entry__ lea(rbot, monitor_block_bot);    // points to word before bottom// of monitor block__ jmpb(entry);__ bind(loop);// check if current entry is for same object__ cmpptr(rax, Address(rtop, BasicObjectLock::obj_offset_in_bytes()));// if same object then stop searching__ jcc(Assembler::equal, found);// otherwise advance to next entry__ addptr(rtop, entry_size);__ bind(entry);// check if bottom reached__ cmpptr(rtop, rbot);// if not at bottom then check this entry__ jcc(Assembler::notEqual, loop);}// error handling. Unlocking was not block-structured__ call_VM(noreg, CAST_FROM_FN_PTR(address,InterpreterRuntime::throw_illegal_monitor_state_exception));__ should_not_reach_here();// call run-time routine__ bind(found);__ push_ptr(rax); // make sure object is on stack (contract with oopMaps)__ unlock_object(rtop);__ pop_ptr(rax); // discard object
}

 

monitorexit 里面 unlock_object 之前对应的汇编如下 

lldb) dis -s 0x000000010604fde0 -c 2000x10604fde0: popq   %rax0x10604fde1: cmpq   (%rax), %rax// rtop = expressionBottom// rbot = oldExpressionBottom0x10604fde4: movq   -0x48(%rbp), %rsi0x10604fde8: leaq   -0x48(%rbp), %rdx0x10604fdec: jmp    0x10604fdfc// BasicLockObject's loop// if (found) goto 0x1060500d8;0x10604fdee: cmpq   0x8(%rsi), %rax0x10604fdf2: je     0x1060500d80x10604fdf8: addq   $0x10, %rsi0x10604fdfc: cmpq   %rdx, %rsi0x10604fdff: jne    0x10604fdee// if (!found) InterpreterRuntime::throw_illegal_monitor_state_exception0x10604fe01: callq  0x10604fe0b0x10604fe06: jmp    0x1060500610x10604fe0b: leaq   0x8(%rsp), %rax0x10604fe10: movq   %r13, -0x40(%rbp)0x10604fe14: cmpq   $0x0, -0x10(%rbp)0x10604fe1c: je     0x10604fe990x10604fe22: movq   %rsp, -0x28(%rsp)0x10604fe27: subq   $0x80, %rsp0x10604fe2e: movq   %rax, 0x78(%rsp)0x10604fe33: movq   %rcx, 0x70(%rsp)0x10604fe38: movq   %rdx, 0x68(%rsp)0x10604fe3d: movq   %rbx, 0x60(%rsp)0x10604fe42: movq   %rbp, 0x50(%rsp)0x10604fe47: movq   %rsi, 0x48(%rsp)0x10604fe4c: movq   %rdi, 0x40(%rsp)0x10604fe51: movq   %r8, 0x38(%rsp)0x10604fe56: movq   %r9, 0x30(%rsp)0x10604fe5b: movq   %r10, 0x28(%rsp)0x10604fe60: movq   %r11, 0x20(%rsp)0x10604fe65: movq   %r12, 0x18(%rsp)0x10604fe6a: movq   %r13, 0x10(%rsp)0x10604fe6f: movq   %r14, 0x8(%rsp)0x10604fe74: movq   %r15, (%rsp)0x10604fe78: movabsq $0x1048984ed, %rdi        ; imm = 0x1048984ED 0x10604fe82: movabsq $0x10604fe22, %rsi        ; imm = 0x10604FE22 0x10604fe8c: movq   %rsp, %rdx0x10604fe8f: andq   $-0x10, %rsp0x10604fe93: callq  0x10436af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x10604fe98: hlt    0x10604fe99: pushq  %r100x10604fe9b: cmpq   -0x15398b2(%rip), %r12    ; Universe::_narrow_ptrs_base0x10604fea2: je     0x10604ff1f0x10604fea8: movq   %rsp, -0x28(%rsp)0x10604fead: subq   $0x80, %rsp0x10604feb4: movq   %rax, 0x78(%rsp)0x10604feb9: movq   %rcx, 0x70(%rsp)0x10604febe: movq   %rdx, 0x68(%rsp)0x10604fec3: movq   %rbx, 0x60(%rsp)0x10604fec8: movq   %rbp, 0x50(%rsp)0x10604fecd: movq   %rsi, 0x48(%rsp)0x10604fed2: movq   %rdi, 0x40(%rsp)0x10604fed7: movq   %r8, 0x38(%rsp)0x10604fedc: movq   %r9, 0x30(%rsp)0x10604fee1: movq   %r10, 0x28(%rsp)0x10604fee6: movq   %r11, 0x20(%rsp)0x10604feeb: movq   %r12, 0x18(%rsp)0x10604fef0: movq   %r13, 0x10(%rsp)0x10604fef5: movq   %r14, 0x8(%rsp)0x10604fefa: movq   %r15, (%rsp)0x10604fefe: movabsq $0x1048d4efc, %rdi        ; imm = 0x1048D4EFC 0x10604ff08: movabsq $0x10604fea8, %rsi        ; imm = 0x10604FEA8 0x10604ff12: movq   %rsp, %rdx0x10604ff15: andq   $-0x10, %rsp0x10604ff19: callq  0x10436af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x10604ff1e: hlt    0x10604ff1f: popq   %r100x10604ff21: movq   %r15, %rdi0x10604ff24: movq   %rbp, 0x218(%r15)0x10604ff2b: movq   %rax, 0x208(%r15)0x10604ff32: testl  $0xf, %esp0x10604ff38: je     0x10604ff500x10604ff3e: subq   $0x8, %rsp0x10604ff42: callq  0x1040d2a40               ; InterpreterRuntime::throw_illegal_monitor_state_exception at interpreterRuntime.cpp:6800x10604ff47: addq   $0x8, %rsp0x10604ff4b: jmp    0x10604ff550x10604ff50: callq  0x1040d2a40               ; InterpreterRuntime::throw_illegal_monitor_state_exception at interpreterRuntime.cpp:6800x10604ff55: pushq  %rax0x10604ff56: pushq  %rdi0x10604ff57: pushq  %rsi0x10604ff58: pushq  %rdx0x10604ff59: pushq  %rcx0x10604ff5a: pushq  %r80x10604ff5c: pushq  %r90x10604ff5e: pushq  %r100x10604ff60: pushq  %r110x10604ff62: testl  $0xf, %esp0x10604ff68: je     0x10604ff800x10604ff6e: subq   $0x8, %rsp0x10604ff72: callq  0x103803ae0               ; Thread::current at thread.hpp:6600x10604ff77: addq   $0x8, %rsp0x10604ff7b: jmp    0x10604ff850x10604ff80: callq  0x103803ae0               ; Thread::current at thread.hpp:6600x10604ff85: popq   %r110x10604ff87: popq   %r100x10604ff89: popq   %r90x10604ff8b: popq   %r80x10604ff8d: popq   %rcx0x10604ff8e: popq   %rdx0x10604ff8f: popq   %rsi0x10604ff90: popq   %rdi0x10604ff91: cmpq   %rax, %r150x10604ff94: je     0x1060500110x10604ff9a: movq   %rsp, -0x28(%rsp)0x10604ff9f: subq   $0x80, %rsp0x10604ffa6: movq   %rax, 0x78(%rsp)0x10604ffab: movq   %rcx, 0x70(%rsp)0x10604ffb0: movq   %rdx, 0x68(%rsp)0x10604ffb5: movq   %rbx, 0x60(%rsp)0x10604ffba: movq   %rbp, 0x50(%rsp)0x10604ffbf: movq   %rsi, 0x48(%rsp)0x10604ffc4: movq   %rdi, 0x40(%rsp)0x10604ffc9: movq   %r8, 0x38(%rsp)0x10604ffce: movq   %r9, 0x30(%rsp)0x10604ffd3: movq   %r10, 0x28(%rsp)0x10604ffd8: movq   %r11, 0x20(%rsp)0x10604ffdd: movq   %r12, 0x18(%rsp)0x10604ffe2: movq   %r13, 0x10(%rsp)0x10604ffe7: movq   %r14, 0x8(%rsp)0x10604ffec: movq   %r15, (%rsp)0x10604fff0: movabsq $0x1048d5043, %rdi        ; imm = 0x1048D5043 0x10604fffa: movabsq $0x10604ff9a, %rsi        ; imm = 0x10604FF9A 0x106050004: movq   %rsp, %rdx0x106050007: andq   $-0x10, %rsp0x10605000b: callq  0x10436af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x106050010: hlt    0x106050011: popq   %rax0x106050012: movabsq $0x0, %r100x10605001c: movq   %r10, 0x208(%r15)0x106050023: movabsq $0x0, %r100x10605002d: movq   %r10, 0x218(%r15)0x106050034: movabsq $0x0, %r100x10605003e: movq   %r10, 0x210(%r15)0x106050045: cmpq   $0x0, 0x8(%r15)0x10605004d: je     0x1060500580x106050053: jmp    0x1060007a00x106050058: movq   -0x40(%rbp), %r130x10605005c: movq   -0x38(%rbp), %r140x106050060: retq   0x106050061: movq   %rsp, -0x28(%rsp)0x106050066: subq   $0x80, %rsp0x10605006d: movq   %rax, 0x78(%rsp)0x106050072: movq   %rcx, 0x70(%rsp)0x106050077: movq   %rdx, 0x68(%rsp)0x10605007c: movq   %rbx, 0x60(%rsp)0x106050081: movq   %rbp, 0x50(%rsp)0x106050086: movq   %rsi, 0x48(%rsp)0x10605008b: movq   %rdi, 0x40(%rsp)0x106050090: movq   %r8, 0x38(%rsp)0x106050095: movq   %r9, 0x30(%rsp)0x10605009a: movq   %r10, 0x28(%rsp)0x10605009f: movq   %r11, 0x20(%rsp)0x1060500a4: movq   %r12, 0x18(%rsp)0x1060500a9: movq   %r13, 0x10(%rsp)0x1060500ae: movq   %r14, 0x8(%rsp)0x1060500b3: movq   %r15, (%rsp)0x1060500b7: movabsq $0x1047f2a69, %rdi        ; imm = 0x1047F2A69 0x1060500c1: movabsq $0x106050061, %rsi        ; imm = 0x106050061 0x1060500cb: movq   %rsp, %rdx0x1060500ce: andq   $-0x10, %rsp0x1060500d2: callq  0x10436af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x1060500d7: hlt// unlock_object0x1060500d8: pushq  %rax0x1060500d9: movq   %r13, -0x40(%rbp)0x1060500dd: leaq   (%rsi), %rax

别看这里 贴了这么多汇编出来, 实际核心的处理主要是 BasicLockObject's loop 这一段 

查询 BasicLockObject 列表, 寻找 BasicLockObject.obj 为 lockObj 的记录, 然后 交给后面的 unlock_object 处理 

如果找不到 表示还没有获取到锁, 抛出 IllegalStateException

 

 

unlock_object 的业务

interp_masm_x86.cpp unlock_object 

// Unlocks an object. Used in monitorexit bytecode and
// remove_activation.  Throws an IllegalMonitorException if object is
// not locked by current thread.
//
// Args:
//      rdx, c_rarg1: BasicObjectLock for lock
//
// Kills:
//      rax
//      c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs)
//      rscratch1 (scratch reg)
// rax, rbx, rcx, rdx
void InterpreterMacroAssembler::unlock_object(Register lock_reg) {assert(lock_reg == LP64_ONLY(c_rarg1) NOT_LP64(rdx),"The argument is only for looks. It must be c_rarg1");if (UseHeavyMonitors) {call_VM(noreg,CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit),lock_reg);} else {Label done;const Register swap_reg   = rax;  // Must use rax for cmpxchg instructionconst Register header_reg = LP64_ONLY(c_rarg2) NOT_LP64(rbx);  // Will contain the old oopMarkconst Register obj_reg    = LP64_ONLY(c_rarg3) NOT_LP64(rcx);  // Will contain the oopsave_bcp(); // Save in case of exception// Convert from BasicObjectLock structure to object and BasicLock// structure Store the BasicLock address into %raxlea(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes()));// Load oop into obj_reg(%c_rarg3)movptr(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()));// Free entrymovptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD);if (UseBiasedLocking) {biased_locking_exit(obj_reg, header_reg, done);}// Load the old header from BasicLock structuremovptr(header_reg, Address(swap_reg,BasicLock::displaced_header_offset_in_bytes()));// Test for recursiontestptr(header_reg, header_reg);// zero for recursive casejcc(Assembler::zero, done);// Atomic swap back the old headerif (os::is_MP()) lock();cmpxchgptr(header_reg, Address(obj_reg, 0));// zero for simple unlock of a stack-lock casejcc(Assembler::zero, done);// Call the runtime routine for slow case.movptr(Address(lock_reg, BasicObjectLock::obj_offset_in_bytes()),obj_reg); // restore objcall_VM(noreg,CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit),lock_reg);bind(done);restore_bcp();}
}

 

macroAssembler_x86.cpp biased_locking_exit  

void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {assert(UseBiasedLocking, "why call this otherwise?");// Check for biased locking unlock case, which is a no-op// Note: we do not have to check the thread ID for two reasons.// First, the interpreter checks for IllegalMonitorStateException at// a higher level. Second, if the bias was revoked while we held the// lock, the object could not be rebiased toward another thread, so// the bias bit would be clear.movptr(temp_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));andptr(temp_reg, markOopDesc::biased_lock_mask_in_place);cmpptr(temp_reg, markOopDesc::biased_lock_pattern);jcc(Assembler::equal, done);
}

 

unlock_object 这部分生成的汇编如下 

(lldb) dis -s 0x1060500d8 -c 200
->  0x1060500d8: pushq  %rax// 寄存器映射 : swap_reg = rax, obj_reg = rcx, header_reg = rdx// save_bcp0x1060500d9: movq   %r13, -0x40(%rbp)// rax = BasicObjectLock.lock// rcx = BasicObjectLock.obj// BasicObjectLock.obj = null0x1060500dd: leaq   (%rsi), %rax0x1060500e0: movq   0x8(%rsi), %rcx0x1060500e4: movq   $0x0, 0x8(%rsi)// biased_locking_exit// if(obj.mark().has_bias_pattern()) goto done;0x1060500ec: movq   (%rcx), %rdx0x1060500ef: andq   $0x7, %rdx0x1060500f3: cmpq   $0x5, %rdx0x1060500f7: je     0x106050378// rdx = BasicObjectLock.lock.displaced_header// if(BasicObjectLock.lock.displaced_header == null) goto done;0x1060500fd: movq   (%rax), %rdx0x106050100: testq  %rdx, %rdx0x106050103: je     0x106050378// if(cas(rdx, lockObj.mark_addr, rax)) goto done;0x106050109: lock   0x10605010a: cmpxchgq %rdx, (%rcx)0x10605010e: je     0x106050378// BasicObjectLock.obj = lockObj// InterpreterRuntime::monitorexit0x106050114: movq   %rcx, 0x8(%rsi)0x106050118: callq  0x1060501220x10605011d: jmp    0x1060503780x106050122: leaq   0x8(%rsp), %rax0x106050127: movq   %r13, -0x40(%rbp)0x10605012b: cmpq   $0x0, -0x10(%rbp)0x106050133: je     0x1060501b00x106050139: movq   %rsp, -0x28(%rsp)0x10605013e: subq   $0x80, %rsp0x106050145: movq   %rax, 0x78(%rsp)0x10605014a: movq   %rcx, 0x70(%rsp)0x10605014f: movq   %rdx, 0x68(%rsp)0x106050154: movq   %rbx, 0x60(%rsp)0x106050159: movq   %rbp, 0x50(%rsp)0x10605015e: movq   %rsi, 0x48(%rsp)0x106050163: movq   %rdi, 0x40(%rsp)0x106050168: movq   %r8, 0x38(%rsp)0x10605016d: movq   %r9, 0x30(%rsp)0x106050172: movq   %r10, 0x28(%rsp)0x106050177: movq   %r11, 0x20(%rsp)0x10605017c: movq   %r12, 0x18(%rsp)0x106050181: movq   %r13, 0x10(%rsp)0x106050186: movq   %r14, 0x8(%rsp)0x10605018b: movq   %r15, (%rsp)0x10605018f: movabsq $0x1040984ed, %rdi        ; imm = 0x1040984ED 0x106050199: movabsq $0x106050139, %rsi        ; imm = 0x106050139 0x1060501a3: movq   %rsp, %rdx0x1060501a6: andq   $-0x10, %rsp0x1060501aa: callq  0x103b6af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x1060501af: hlt    0x1060501b0: pushq  %r100x1060501b2: cmpq   -0x1d39bc9(%rip), %r12    ; Universe::_narrow_ptrs_base0x1060501b9: je     0x1060502360x1060501bf: movq   %rsp, -0x28(%rsp)0x1060501c4: subq   $0x80, %rsp0x1060501cb: movq   %rax, 0x78(%rsp)0x1060501d0: movq   %rcx, 0x70(%rsp)0x1060501d5: movq   %rdx, 0x68(%rsp)0x1060501da: movq   %rbx, 0x60(%rsp)0x1060501df: movq   %rbp, 0x50(%rsp)0x1060501e4: movq   %rsi, 0x48(%rsp)0x1060501e9: movq   %rdi, 0x40(%rsp)0x1060501ee: movq   %r8, 0x38(%rsp)0x1060501f3: movq   %r9, 0x30(%rsp)0x1060501f8: movq   %r10, 0x28(%rsp)0x1060501fd: movq   %r11, 0x20(%rsp)0x106050202: movq   %r12, 0x18(%rsp)0x106050207: movq   %r13, 0x10(%rsp)0x10605020c: movq   %r14, 0x8(%rsp)0x106050211: movq   %r15, (%rsp)0x106050215: movabsq $0x1040d4efc, %rdi        ; imm = 0x1040D4EFC 0x10605021f: movabsq $0x1060501bf, %rsi        ; imm = 0x1060501BF 0x106050229: movq   %rsp, %rdx0x10605022c: andq   $-0x10, %rsp0x106050230: callq  0x103b6af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x106050235: hlt    0x106050236: popq   %r100x106050238: movq   %r15, %rdi0x10605023b: movq   %rbp, 0x218(%r15)0x106050242: movq   %rax, 0x208(%r15)0x106050249: testl  $0xf, %esp0x10605024f: je     0x1060502670x106050255: subq   $0x8, %rsp0x106050259: callq  0x1038d2700               ; InterpreterRuntime::monitorexit at interpreterRuntime.cpp:6600x10605025e: addq   $0x8, %rsp0x106050262: jmp    0x10605026c0x106050267: callq  0x1038d2700               ; InterpreterRuntime::monitorexit at interpreterRuntime.cpp:6600x10605026c: pushq  %rax0x10605026d: pushq  %rdi0x10605026e: pushq  %rsi0x10605026f: pushq  %rdx0x106050270: pushq  %rcx0x106050271: pushq  %r80x106050273: pushq  %r90x106050275: pushq  %r100x106050277: pushq  %r110x106050279: testl  $0xf, %esp0x10605027f: je     0x1060502970x106050285: subq   $0x8, %rsp0x106050289: callq  0x103003ae0               ; Thread::current at thread.hpp:6600x10605028e: addq   $0x8, %rsp0x106050292: jmp    0x10605029c0x106050297: callq  0x103003ae0               ; Thread::current at thread.hpp:6600x10605029c: popq   %r110x10605029e: popq   %r100x1060502a0: popq   %r90x1060502a2: popq   %r80x1060502a4: popq   %rcx0x1060502a5: popq   %rdx0x1060502a6: popq   %rsi0x1060502a7: popq   %rdi0x1060502a8: cmpq   %rax, %r150x1060502ab: je     0x1060503280x1060502b1: movq   %rsp, -0x28(%rsp)0x1060502b6: subq   $0x80, %rsp0x1060502bd: movq   %rax, 0x78(%rsp)0x1060502c2: movq   %rcx, 0x70(%rsp)0x1060502c7: movq   %rdx, 0x68(%rsp)0x1060502cc: movq   %rbx, 0x60(%rsp)0x1060502d1: movq   %rbp, 0x50(%rsp)0x1060502d6: movq   %rsi, 0x48(%rsp)0x1060502db: movq   %rdi, 0x40(%rsp)0x1060502e0: movq   %r8, 0x38(%rsp)0x1060502e5: movq   %r9, 0x30(%rsp)0x1060502ea: movq   %r10, 0x28(%rsp)0x1060502ef: movq   %r11, 0x20(%rsp)0x1060502f4: movq   %r12, 0x18(%rsp)0x1060502f9: movq   %r13, 0x10(%rsp)0x1060502fe: movq   %r14, 0x8(%rsp)0x106050303: movq   %r15, (%rsp)0x106050307: movabsq $0x1040d5043, %rdi        ; imm = 0x1040D5043 0x106050311: movabsq $0x1060502b1, %rsi        ; imm = 0x1060502B1 0x10605031b: movq   %rsp, %rdx0x10605031e: andq   $-0x10, %rsp0x106050322: callq  0x103b6af60               ; MacroAssembler::debug64 at macroAssembler_x86.cpp:8620x106050327: hlt    0x106050328: popq   %rax0x106050329: movabsq $0x0, %r100x106050333: movq   %r10, 0x208(%r15)0x10605033a: movabsq $0x0, %r100x106050344: movq   %r10, 0x218(%r15)0x10605034b: movabsq $0x0, %r100x106050355: movq   %r10, 0x210(%r15)0x10605035c: cmpq   $0x0, 0x8(%r15)0x106050364: je     0x10605036f0x10605036a: jmp    0x1060007a00x10605036f: movq   -0x40(%rbp), %r130x106050373: movq   -0x38(%rbp), %r140x106050377: retq// done; 0x106050378: movq   -0x40(%rbp), %r130x10605037c: popq   %rax0x10605037d: movzbl 0x1(%r13), %ebx0x106050382: incq   %r130x106050385: movabsq $0x10430b270, %r10        ; imm = 0x10430B270 0x10605038f: jmpq   *(%r10,%rbx,8)0x106050393: nop    0x106050394: nop    

 

通过以上的汇编代码块, 可以整理出一些规则 

1. 如果 obj 上面是偏向锁, 那么什么都不用做, 直接 done 

2. 如果 obj 对应的 BasicObjectLock.lock.displaced_header 为 null(轻量级锁重入的情况), 直接 done 

3. 如果 obj 对应的 locker 为 BasicObjectLock.lock, cas 替换其 mark 为 BasicObjectLock.lock.displaced_header 当前 直接 done 

4. 走 InterpreterRuntime::monitorexit 

 

我们这里的偏向锁退出, 直接走的是 1, 检查了一下 锁标记位 和 偏向锁 标记位, 然后 done 

* thread #5, stop reason = breakpoint 4.1frame #0: 0x00000001060500ec
->  0x1060500ec: movq   (%rcx), %rdx0x1060500ef: andq   $0x7, %rdx0x1060500f3: cmpq   $0x5, %rdx0x1060500f7: je     0x106050378
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:rax = 0x0000700006a3c628rbx = 0x00000000000000c3rcx = 0x0000000747bb86a0rdx = 0x0000700006a3c638rdi = 0x0000000101003800rsi = 0x0000700006a3c628rbp = 0x0000700006a3c680rsp = 0x0000700006a3c620r8 = 0x0000000000000000r9 = 0x0000000000000020r10 = 0x0000000104b0aa70  libjvm.dylib`TemplateInterpreter::_active_table + 16384r11 = 0x00006fff05a37c00r12 = 0x0000000000000000r13 = 0x000000011e267f95r14 = 0x0000700006a3c6a8r15 = 0x0000000101003800rip = 0x00000001060500ecrflags = 0x0000000000000246cs = 0x000000000000002bfs = 0x0000000000000000gs = 0x0000000000000000(lldb) x 0x0000000747bb86a0
0x747bb86a0: 05 38 00 01 01 00 00 00 86 1f 01 f8 00 00 00 00  .8.........?....
0x747bb86b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x00000001060500ef
->  0x1060500ef: andq   $0x7, %rdx0x1060500f3: cmpq   $0x5, %rdx0x1060500f7: je     0x1060503780x1060500fd: movq   (%rax), %rdx
Target 0: (java) stopped.
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x00000001060500f3
->  0x1060500f3: cmpq   $0x5, %rdx0x1060500f7: je     0x1060503780x1060500fd: movq   (%rax), %rdx0x106050100: testq  %rdx, %rdx
Target 0: (java) stopped.
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x00000001060500f7
->  0x1060500f7: je     0x1060503780x1060500fd: movq   (%rax), %rdx0x106050100: testq  %rdx, %rdx0x106050103: je     0x106050378
Target 0: (java) stopped.
(lldb) stepi
Process 2662 stopped
* thread #5, stop reason = instruction step intoframe #0: 0x0000000106050378
->  0x106050378: movq   -0x40(%rbp), %r130x10605037c: popq   %rax0x10605037d: movzbl 0x1(%r13), %ebx0x106050382: incq   %r13
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb86a0)->print()
com.hx.test04.Test26SynchronizeObject 
{0x0000000747bb86a0} - klass: 'com/hx/test04/Test26SynchronizeObject'- ---- fields (total size 5 words):- 'f01' 'I' @12  0- 'f02' 'I' @16  0- 'f03' 'I' @20  0- 'f04' 'I' @24  0- 'f05' 'I' @28  0- private 'identStr' 'Ljava/lang/String;' @32  "xyz"{0x0000000747bb86c8} (e8f770d9 0)
(lldb) p ((oopDesc*)0x0000000747bb86a0)->mark()->has_bias_pattern()
(bool) $2 = true
(lldb) p ((oopDesc*)0x0000000747bb86a0)->mark()->biased_locker()->threadObj()->print()
java.lang.Thread 
{0x0000000747f069d8} - klass: 'java/lang/Thread'- ---- fields (total size 47 words):- private 'priority' 'I' @12  5- private 'eetop' 'J' @16  4311758848 (1003800 1)- private 'stackSize' 'J' @24  0 (0 0)- private 'nativeParkEventPointer' 'J' @32  0 (0 0)- private 'tid' 'J' @40  1 (1 0)- private volatile 'threadStatus' 'I' @48  5- private 'single_step' 'Z' @52  false- private 'daemon' 'Z' @53  false- private 'stillborn' 'Z' @54  false- private volatile 'name' 'Ljava/lang/String;' @56  "main"{0x0000000747f06b50} (e8fe0d6a 0)- private 'threadQ' 'Ljava/lang/Thread;' @60  NULL (0 0)- private 'target' 'Ljava/lang/Runnable;' @64  NULL (0 e8fe0c85)- private 'group' 'Ljava/lang/ThreadGroup;' @68  a 'java/lang/ThreadGroup'{0x0000000747f06428} (e8fe0c85 e8fc0af7)- private 'contextClassLoader' 'Ljava/lang/ClassLoader;' @72  a 'jdk/internal/loader/ClassLoaders$AppClassLoader'{0x0000000747e057b8} (e8fc0af7 e8fe0d91)- private 'inheritedAccessControlContext' 'Ljava/security/AccessControlContext;' @76  a 'java/security/AccessControlContext'{0x0000000747f06c88} (e8fe0d91 e8fe2fb8)- 'threadLocals' 'Ljava/lang/ThreadLocal$ThreadLocalMap;' @80  a 'java/lang/ThreadLocal$ThreadLocalMap'{0x0000000747f17dc0} (e8fe2fb8 0)- 'inheritableThreadLocals' 'Ljava/lang/ThreadLocal$ThreadLocalMap;' @84  NULL (0 0)- volatile 'parkBlocker' 'Ljava/lang/Object;' @88  NULL (0 0)- private volatile 'blocker' 'Lsun/nio/ch/Interruptible;' @92  NULL (0 e8fe0d70)- private final 'blockerLock' 'Ljava/lang/Object;' @96  a 'java/lang/Object'{0x0000000747f06b80} (e8fe0d70 0)- private volatile 'uncaughtExceptionHandler' 'Ljava/lang/Thread$UncaughtExceptionHandler;' @100  NULL (0 0)- 'threadLocalRandomSeed' 'J' @232  0 (0 0)- 'threadLocalRandomProbe' 'I' @240  0- 'threadLocalRandomSecondarySeed' 'I' @244  0

 

 

完 

 

 

参考

09 给对象添加偏向锁的调试

 

 

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 自动驾驶_高精地图模型构成

    ...

    2024/3/14 0:52:59
  2. 十四、垃圾回收概述

    1、什么是垃圾垃圾收集,不是Java语言的伴生产物。早在1960年,第一门开始使用内存动态分配和垃圾收集技术的Lisp语言诞生。关于垃圾收集有三个经典问题: 哪些内存需要回收?什么时候回收?如何回收? 垃圾收集机制是Java的招牌能力,极大地提高了开发效率。如今,垃圾收集几乎成为…...

    2024/3/14 0:52:58
  3. python thrift 实现 单端口多服务

    前言 学习了两天thrift 一直想实现单端口多服务 但是苦于网上的 thrift 实在太少 而且大部分都是java实现的 最后 改了一个java的 实现了 单端口多服务 实现过程 1 创建 thrift 文件 添加两个服务 Transmit Hello_test service Transmit { string invoke(1:i32 cmd 2:st…...

    2024/3/14 0:53:00
  4. Yet Another Bracket Sequence(线段树)

    题目描述 One day, Little Gyro was playing with a series of Bracket Sequences, A Bracket Sequence is a string that only contains two kinds of characters ‘(’ and ‘)’. Let us define a regular Bracket Sequence in the following way: Empty sequence is a regu…...

    2024/3/14 10:07:01
  5. 团队聚会

    团队聚会 题目描述TA团队每周都会有很多任务,有的可以单独完成,有的则需要所有人聚到一起,开过会之后才能去做。但TA团队的每个成员都有各自的事情,找到所有人都有空的时间段并不是一件容易的事情。 给出每位助教的各项事情的时间表,你的任务是找出所有可以用来开会的时间…...

    2024/3/14 10:07:05
  6. 剑指offer--从头到尾打印链表

    题目: 输入一个链表,按链表从尾到头的顺序返回一个ArrayList。 思路: 遍历的顺序是从头到尾的顺序,可输出的顺序却是从尾到头。也就是说第一个遍历到的结点最后一个输出,而最后一个遍历到的结点第一个输出。这就是典型的“后进先出”,我们可以用栈实现这种顺序。每经过一…...

    2024/3/14 10:06:58
  7. 进程的几种状态

    图片来源于网络挂起:又称为阻塞;如图所示,挂起的时候,是等待出CPU以外的其他资源主动放弃cpu,其他资源指的是,read函数的阻塞,阻塞的时候是放弃了cpu,等待缓冲区内的数据。进程的4中状态是保存在PCB结构体中的。...

    2024/3/14 10:07:06
  8. Keras训练出现:StopIteration: image file is truncated

    报错原因:图像文件被截断;解决方法:在前面加载模块的地方添加两行代码from PIL import ImageFile ImageFile.LOAD_TRUNCATED_IMAGES = True...

    2024/3/14 10:06:52
  9. Stream流之List、Integer[]、int[]相互转化

    Stream流之List、Integer[]、int[]相互转化 一、int[ ] 1.1、int[ ] 转 Integer[ ] public static void main(String[] args) {int[] arr = { 1, 2, 3, 4, 5 };List<Integer> list = Arrays.stream(arr).boxed().collect(Collectors.toList());list.forEach(e -> Syst…...

    2024/3/14 10:06:51
  10. 快速排序算法,并输出每一轮后数据位置的交换

    快速排序算法 #include <stdio.h> #include <stdlib.h> #define MAXSIZE 20//顺序表长度 typedef int KeyType; typedef struct {KeyType Key; }RcdType; typedef struct {RcdType r[MAXSIZE+1];int length; }SqList; void swap(RcdType &r1,RcdType &r2) …...

    2024/3/14 10:07:02
  11. MySQL数据库基础

    数据库的操作 显示当前数据库: SHOW DATABASES;创建数据库: CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification]...]create_specification:[DEFAULT] CHARACTER SET charset_name[DEFAULT] COLLATE collation_name--大写表示关键字 --…...

    2024/3/14 10:06:51
  12. PTA 修建道路 (30分)

    修建道路 (30分)代码长度限制 16 KB 时间限制 1000 ms 内存限制 64 MB题目描述: N个村庄,从1到N编号,现在请您兴建一些路使得任何两个村庄彼此连通。我们称村庄A和B是连通的,当且仅当在A和B之间存在一条路,或者存在一个存在C,使得A和C之间有一条路,并且C和B是连通…...

    2024/3/14 10:06:54
  13. 指针的笔试题详解

    笔试题1: int main() {int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));return 0; }vs2013的运行结果:笔试题二: struct Test { int Num; char *pcName; short sDate; char cha[2]; short sBa[4]; }*p; //假…...

    2024/3/14 10:07:08
  14. KMP模板

    KMP ​ KMP算法每当一趟匹配过程中出现字符比较不等时,主串S中的i指针不需回溯,而是利用已经得到的“部分匹配”结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。 ​ KMP算法的主要核心其实就是next数组的求解 next数组求解 void GetNext(char *w, int next[]) {…...

    2024/3/22 18:39:20
  15. 抓住时间1-在mysql数据库中获取当前日期时间

    胖子没有夏天,英俊如我亦唯有时间。逝者如斯夫,不舍昼夜。1 抓不住的时间是谁在说抓不住时间,看如何在MySql及其分支数据库里下获取当前时间。 Percona官网地址:http://www.percona.com/ Maridb官网地址:https://mariadb.org/MySql处理日期和时间函数众多,简单介绍3类获取…...

    2024/3/14 10:06:54
  16. Linux中VIM编辑器的使用

    VIM编辑器 vim的工作模式vim编辑器的使用光标移动翻页 Page Down或Ctrl+F 向下翻动- -整页内容Page Up或Ctrl+B 向上翻动一整页内容行内跳转 Home键或“A”、 数字“0” 跳转至行首End键或“$"键 跳转到行尾#—> 向右移动#个字符#<— 向左移动#个字符行间跳转 1G或者…...

    2024/3/22 4:50:55
  17. 计算机网络(27)——交换机

    交换机链路层设备存储-转发以太网帧检测到达帧的目的MAC地址,选择性向一个或多个输出链路转发帧利用CSMA/CD访问链路,发送帧透明主机感知不到交换机的存在即插即用自学习——交换机无需配置多端口间同时传输主机利用独享链路直接连接交换机交换机缓存帧交换机在每段链路上利用…...

    2024/3/14 0:53:14
  18. c++11设计模式 对象池模式 可变参数构造 自动析构

    当程序中需要用到一定数量的对象,且创建对象开销比较大时可以考虑使用对象池模式。和线程池类型,需要预先创建一定数量的对象,上层使用时可以从池子中获取创建好的对象。本文的对象池模式实现可变参数构造对象,使用完成之后自动析构。 #include <functional> #includ…...

    2024/3/14 0:53:10
  19. uniapp动态路由传参(传递对象)

    不多说废话,直接上代码: 如果是传递某一个参数 uniapp路由跳转写法: openWeb(id){uni.navigateTo({url:/pages/index/index?id= + id }); // 这个id就是需要传递过去的参数 }但是我们如果要传递两个或者多个参数呢,写法都差不多,但是需要用上JSON.stringify(); openWeb…...

    2024/3/26 16:58:47
  20. 十二种数组去重方法

    JavaScript数组去重 一、利用ES6 Set去重(ES6中最常用) function unique (arr) {return Array.from(new Set(arr)) } var arr = [1,1,true,true,true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,NaN, 0, 0, a, a,{},{}]; console.log(unique(arr))//…...

    2024/3/14 0:53:09

最新文章

  1. stamac Ethernet DTS配置

    目录 Demo 配置 compatible reg interrupts & interrupt-names phy-mode phy-handle Snps,reset-gpio...

    2024/3/29 5:14:41
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 富格林:可信操作阻挠做单亏损

    富格林认为&#xff0c;近年来现货黄金作为具有避险属性的投资产品备受投资者的青睐&#xff0c;新手投资者也纷纷加入其中。但是由于新手投资者缺乏控制仓位的可信经验而无法阻挠做单出现亏损的情况。因此&#xff0c;建议新手投资者应了解如何进行控仓来阻挠出金亏损的状况。…...

    2024/3/29 5:00:24
  4. Linux系统使用Docker部署Portainer结合内网穿透实现远程管理容器和镜像

    &#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

    2024/3/29 2:00:14
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/3/27 10:21:24
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/3/24 20:11:25
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/3/29 2:45:46
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/3/24 20:11:23
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/3/26 20:58:42
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/3/28 17:01:12
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/3/24 5:55:47
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/3/29 1:13:26
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/3/26 23:04:51
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/3/26 11:20:25
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/3/24 20:11:18
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/3/28 9:10:53
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/3/29 0:49:46
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/3/24 20:11:15
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/3/27 7:12:50
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/3/24 20:11:13
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/3/26 11:21:23
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/3/28 18:26:34
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/3/28 12:42:28
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/3/28 20:09:10
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57