JVM Stack
Stack
参考SharkStack类,代码:hotspot\src\share\vm\shark\sharkStack.hpp
栈帧
每个方法调用都对应一个栈帧(frame )。包含本地变量表,操作栈(operand stack),当前调用的方法对应类的运行时常量池(run-time constant pool)的引用(reference)。
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6 写道
A frame may be extended with additional implementation-specific information, such as debugging information.
本地变量表使用一个数组保存每一个本地变量(local variable)。
本地变量表和操作栈 的大小在编译期就已确定。
本地变量表
操作栈
参考SharkState类,代码:hotspot\src\share\vm\shark\sharkState.hpp
参考代码:hotspot\src\share\vm\shark\sharkStateScanner.cpp
void SharkStateScanner::scan(SharkState* state) {
start_frame();
// Expression stack
stack_integrity_checks(state);
start_stack(state->stack_depth());
for (int i = state->stack_depth() - 1; i >= 0; i--) {
process_stack_slot(
i,
state->stack_addr(i),
stack()->stack_slots_offset() +
i + max_stack() - state->stack_depth());
}
end_stack();
// Monitors
start_monitors(state->num_monitors());
for (int i = 0; i < state->num_monitors(); i++) {
process_monitor(
i,
stack()->monitor_offset(i),
stack()->monitor_object_offset(i));
}
end_monitors();
// Frame header
start_frame_header();
process_oop_tmp_slot(
state->oop_tmp_addr(), stack()->oop_tmp_slot_offset());
process_method_slot(state->method_addr(), stack()->method_slot_offset());
process_pc_slot(stack()->pc_slot_offset());
end_frame_header();
// Local variables
locals_integrity_checks(state);
start_locals();
for (int i = 0; i < max_locals(); i++) {
process_local_slot(
i,
state->local_addr(i),
stack()->locals_slots_offset() + max_locals() - 1 - i);
}
end_locals();
end_frame();
}
public static void main(String[] args) {
apply(1);
}
private static void apply(int arg) {
int argc = arg;
try {
apply(++arg);
} catch(Throwable e) {
System.out.println(argc);
System.out.println(e);
}
}
5617
java.lang.StackOverflowError
将System.out.println(e);改成e.printStackTrace();打印出栈信息:
5617
java.lang.StackOverflowError
at sparktest.StackTest.apply(StackTest.java:14)
at sparktest.StackTest.apply(StackTest.java:12)
at sparktest.StackTest.apply(StackTest.java:12)
at sparktest.StackTest.apply(StackTest.java:12)
at sparktest.StackTest.apply(StackTest.java:12)
at sparktest.StackTest.apply(StackTest.java:12)
at sparktest.StackTest.apply(StackTest.java:12)
at sparktest.StackTest.apply(StackTest.java:12)
at sparktest.StackTest.apply(StackTest.java:12)
at sparktest.StackTest.apply(StackTest.java:12)
at sparktest.StackTest.apply(StackTest.java:12)
...
java call
java call包括special,virtual,Static方法调用。这些方法调用都会调用到Low-level的call函数:
static void call(JavaValue* result, methodHandle method, JavaCallArguments* args, TRAPS);
另外还有一个call_helper方法:
static void call_helper(JavaValue* result, methodHandle* method, JavaCallArguments* args, TRAPS);
上面的Low-level的call函数通过java_call_t的函数指针调用call_helper函数。
java_call_t
java_call_t被定义成一个函数指针,用来表示java调用。如调用java的方法,包括virtual方法调用,特定(special)方法调用,静态(static)方法调用。
其中virtual方法,特定(special)方法都是普通的非静态方法。这里的virtual方法,特定(special)方法,静态(static)方法就是java代码编译成字节码后方法调用的地方常见的invokespecial,invokevirtual,invokestatic指令。这些指令参考另一篇文章:https://lobin.iteye.com/blog/2440503。
typedef void (*java_call_t)(JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread);
java call(special)
// call_special
// ------------
// The receiver must be first oop in argument list
static void call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS);
static void call_special(JavaValue* result, Handle receiver, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); // No args
static void call_special(JavaValue* result, Handle receiver, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, TRAPS);
static void call_special(JavaValue* result, Handle receiver, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, Handle arg2, TRAPS);
java call(virtual)
// virtual call
// ------------
// The receiver must be first oop in argument list
static void call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS);
static void call_virtual(JavaValue* result, Handle receiver, KlassHandle spec_klass, Symbol* name, Symbol* signature, TRAPS); // No args
static void call_virtual(JavaValue* result, Handle receiver, KlassHandle spec_klass, Symbol* name, Symbol* signature, Handle arg1, TRAPS);
static void call_virtual(JavaValue* result, Handle receiver, KlassHandle spec_klass, Symbol* name, Symbol* signature, Handle arg1, Handle arg2, TRAPS);
java call(Static)
// Static call
// -----------
static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS);
static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, TRAPS);
static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, Handle arg2, TRAPS);
call_helper函数将java call封装成JavaCallWrapper,然后通过一个调用代理CallStub(调用StubRoutines::call_stub()函数得到这个CallStub调用代理)。
调用代理(CallStub)
StubRoutines::call_stub()函数:
static CallStub call_stub() { return CAST_TO_FN_PTR(CallStub, _call_stub_entry); }
其中:
#define CAST_TO_FN_PTR(func_type, value) ((func_type)(castable_address(value)))
展开后:
static CallStub call_stub() { return ((CallStub)(castable_address(_call_stub_entry)));}
_call_stub_entry由StubGenerator extends StubCodeGenerator初始化,参考generate_call_stub函数,它返回的是调用代理的第一条指令的地址(address),也就是在调用这个调用代理时要跳转到的目标地址,以及调用这个调用代理后要跳转返回的地址,为调用代理(这个调用代理可以理解为一段汇编指令程序,负责代理调用方法)建栈(见__ enter();...__ pop(rbp);),传递参数,方法调用时call指令要跳转到的目标地址。
在看JVM在实现汇编指令等价函数操作时,和汇编指令语法一样,也有它的汇编风格,参考AT&T汇编风格。
调用代理(CallStub)也是一个函数指针
// Calls to Java
typedef void (*CallStub)(
address link,
intptr_t* result,
BasicType result_type,
methodOopDesc* method,
address entry_point,
intptr_t* parameters,
int size_of_parameters,
TRAPS
);
jmethodID -> methodHandle -> JavaCalls::call -> StubRoutines::call_stub -> CallStub ->
CallStub
64位x86 CPU实现:generate_call_stub
参考src\cpu\x86\vm\stubGenerator_x86_64.cpp
address 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
for (int i = 6; i <= 15; 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, MXCSR_MASK); // Only check control and mask bits
ExternalAddress mxcsr_std(StubRoutines::x86::mxcsr_std());
__ cmp32(rax, mxcsr_std);
__ jcc(Assembler::equal, skip_ldmx);
__ ldmxcsr(mxcsr_std);
__ 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()), (int32_t)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 methodOop
__ 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 L, S;
__ cmpptr(r15_thread, thread);
__ jcc(Assembler::notEqual, S);
__ get_thread(rbx);
__ cmpptr(r15_thread, rbx);
__ jcc(Assembler::equal, L);
__ bind(S);
__ jcc(Assembler::equal, L);
__ stop("StubRoutines::call_stub: threads must correspond");
__ bind(L);
}
#endif
// restore regs belonging to calling function
#ifdef _WIN64
for (int i = 15; i >= 6; 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
__ 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;
}
Assembler
MacroAssembler -》Assembler -》AbstractAssembler
AbstractAssembler:
hotspot\src\share\vm\asm\assembler.hpp
x86:
MacroAssembler:
hotspot\src\cpu\x86\vm\assembler_x86.hpp
Assembler:
hotspot\src\cpu\x86\vm\assembler_x86.hpp
sparc:
AbstractAssembler声明如下:
// Instruction boundaries (required when emitting relocatable values).
class InstructionMark: public StackObj {
private:
AbstractAssembler* _assm;
public:
InstructionMark(AbstractAssembler* assm) : _assm(assm) {
assert(assm->inst_mark() == NULL, "overlapping instructions");
_assm->set_inst_mark();
}
~InstructionMark() {
_assm->clear_inst_mark();
}
};
friend class InstructionMark;
#ifdef ASSERT
// Make it return true on platforms which need to verify
// instruction boundaries for some operations.
inline static bool pd_check_instruction_mark();
// Add delta to short branch distance to verify that it still fit into imm8.
int _short_branch_delta;
int short_branch_delta() const { return _short_branch_delta; }
void set_short_branch_delta() { _short_branch_delta = 32; }
void clear_short_branch_delta() { _short_branch_delta = 0; }
class ShortBranchVerifier: public StackObj {
private:
AbstractAssembler* _assm;
public:
ShortBranchVerifier(AbstractAssembler* assm) : _assm(assm) {
assert(assm->short_branch_delta() == 0, "overlapping instructions");
_assm->set_short_branch_delta();
}
~ShortBranchVerifier() {
_assm->clear_short_branch_delta();
}
};
#else
// Dummy in product.
class ShortBranchVerifier: public StackObj {
public:
ShortBranchVerifier(AbstractAssembler* assm) {}
};
#endif
// Label functions
void print(Label& L);
public:
// Creation
AbstractAssembler(CodeBuffer* code);
// save end pointer back to code buf.
void sync();
// ensure buf contains all code (call this before using/copying the code)
void flush();
// min and max values for signed immediate ranges
static int min_simm(int nbits) { return -(intptr_t(1) << (nbits - 1)) ; }
static int max_simm(int nbits) { return (intptr_t(1) << (nbits - 1)) - 1; }
// Define some:
static int min_simm10() { return min_simm(10); }
static int min_simm13() { return min_simm(13); }
static int min_simm16() { return min_simm(16); }
// Test if x is within signed immediate range for nbits
static bool is_simm(intptr_t x, int nbits) { return min_simm(nbits) <= x && x <= max_simm(nbits); }
// Define some:
static bool is_simm5( intptr_t x) { return is_simm(x, 5 ); }
static bool is_simm8( intptr_t x) { return is_simm(x, 8 ); }
static bool is_simm10(intptr_t x) { return is_simm(x, 10); }
static bool is_simm11(intptr_t x) { return is_simm(x, 11); }
static bool is_simm12(intptr_t x) { return is_simm(x, 12); }
static bool is_simm13(intptr_t x) { return is_simm(x, 13); }
static bool is_simm16(intptr_t x) { return is_simm(x, 16); }
static bool is_simm26(intptr_t x) { return is_simm(x, 26); }
static bool is_simm32(intptr_t x) { return is_simm(x, 32); }
// Accessors
CodeBuffer* code() const; // _code_section->outer()
CodeSection* code_section() const { return _code_section; }
int sect() const; // return _code_section->index()
address pc() const { return _code_pos; }
int offset() const { return _code_pos - _code_begin; }
int locator() const; // CodeBuffer::locator(offset(), sect())
OopRecorder* oop_recorder() const { return _oop_recorder; }
void set_oop_recorder(OopRecorder* r) { _oop_recorder = r; }
address inst_mark() const;
void set_inst_mark();
void clear_inst_mark();
// Constants in code
void a_byte(int x);
void a_long(jint x);
void relocate(RelocationHolder const& rspec, int format = 0);
void relocate( relocInfo::relocType rtype, int format = 0) {
if (rtype != relocInfo::none)
relocate(Relocation::spec_simple(rtype), format);
}
static int code_fill_byte(); // used to pad out odd-sized code buffers
// Associate a comment with the current offset. It will be printed
// along with the disassembly when printing nmethods. Currently
// only supported in the instruction section of the code buffer.
void block_comment(const char* comment);
// Label functions
void bind(Label& L); // binds an unbound label L to the current code position
// Move to a different section in the same code buffer.
void set_code_section(CodeSection* cs);
// Inform assembler when generating stub code and relocation info
address start_a_stub(int required_space);
void end_a_stub();
// Ditto for constants.
address start_a_const(int required_space, int required_align = sizeof(double));
void end_a_const();
// constants support
address long_constant(jlong c) {
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
*(jlong*)ptr = c;
_code_pos = ptr + sizeof(c);
end_a_const();
}
return ptr;
}
address double_constant(jdouble c) {
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
*(jdouble*)ptr = c;
_code_pos = ptr + sizeof(c);
end_a_const();
}
return ptr;
}
address float_constant(jfloat c) {
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
*(jfloat*)ptr = c;
_code_pos = ptr + sizeof(c);
end_a_const();
}
return ptr;
}
address address_constant(address c) {
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
*(address*)ptr = c;
_code_pos = ptr + sizeof(c);
end_a_const();
}
return ptr;
}
address address_constant(address c, RelocationHolder const& rspec) {
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
relocate(rspec);
*(address*)ptr = c;
_code_pos = ptr + sizeof(c);
end_a_const();
}
return ptr;
}
// Bootstrapping aid to cope with delayed determination of constants.
// Returns a static address which will eventually contain the constant.
// The value zero (NULL) stands instead of a constant which is still uncomputed.
// Thus, the eventual value of the constant must not be zero.
// This is fine, since this is designed for embedding object field
// offsets in code which must be generated before the object class is loaded.
// Field offsets are never zero, since an object's header (mark word)
// is located at offset zero.
RegisterOrConstant delayed_value(int(*value_fn)(), Register tmp, int offset = 0) {
return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset);
}
RegisterOrConstant delayed_value(address(*value_fn)(), Register tmp, int offset = 0) {
return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset);
}
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset) = 0;
// Last overloading is platform-dependent; look in assembler_<arch>.cpp.
static intptr_t* delayed_value_addr(int(*constant_fn)());
static intptr_t* delayed_value_addr(address(*constant_fn)());
static void update_delayed_values();
// Bang stack to trigger StackOverflowError at a safe location
// implementation delegates to machine-specific bang_stack_with_offset
void generate_stack_overflow_check( int frame_size_in_bytes );
virtual void bang_stack_with_offset(int offset) = 0;
/**
* A platform-dependent method to patch a jump instruction that refers
* to this label.
*
* @param branch the location of the instruction to patch
* @param masm the assembler which generated the branch
*/
void pd_patch_instruction(address branch, address target);
#ifndef PRODUCT
/**
* Platform-dependent method of printing an instruction that needs to be
* patched.
*
* @param branch the instruction to be patched in the buffer.
*/
static void pd_print_patched_instruction(address branch);
#endif // PRODUCT
};
JVM 处理器体系
参考文档:https://lobin.iteye.com/blog/2438471
x86
寄存器:
Register rax
rcx
rdx
rbx
rsp
rbp
rsi
rdi
r8
r9
r10
r11
r12
r13
r14
r15
XMMRegister xmm0
xmm1
xmm2
xmm3
xmm4
xmm5
xmm6
xmm7
xmm8
xmm9
xmm10
xmm11
xmm12
xmm13
xmm14
xmm15
MMXRegister mmx0
mmx1
mmx2
mmx3
mmx4
mmx5
mmx6
mmx7
源代码参考如下定义:
#define CONSTANT_REGISTER_DECLARATION(type, name, value) \
extern const type name; \
enum { name##_##type##EnumValue = (value) }
以Register rbp为例,
CONSTANT_REGISTER_DECLARATION(Register, rbp, (5));
预处理阶段展开后:
extern const Register rbp;
enum { rbp_RegisterEnumValue = (5) } ;
PC程序计数器
GC
Java Debug调试工具:jdb
>javac -g StackTest.java
>jdb StackTest
> stop at StackTest:6
> run
print StackTest.arg
stop at StackTest:10
list
threads
cont
where 0x1
Java:构建发布JRE&JDK版本:1.6
参考另一篇文章:https://lobin.iteye.com/blog/620153
1、https://www.oracle.com/technetwork/java/javase/tech/index.html
2、http://openjdk.java.net/projects/mlvm/jvmlangsummit/
3、https://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf
4、https://download.java.net/openjdk/jdk6
5、http://hg.openjdk.java.net/jdk/jdk/raw-file/tip/doc/building.html
6、http://hg.openjdk.java.net/jdk6/jdk6/raw-file/tip/README-builds.html
7、https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
8、The Java Memory Model, http://www.cs.umd.edu/~pugh/java/memoryModel/
9、http://groups.inf.ed.ac.uk/request/jmmexamples.pdf
10、17.4. Memory Model, https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4
11、JSR 133: JavaTM Memory Model and Thread Specification Revision, https://www.jcp.org/en/jsr/detail?id=133
12、https://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/preface.html
13、Troubleshooting Guide for HotSpot VM, https://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/index.html
14、Java HotSpot VM Options, https://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
15、https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
16、https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html
相关推荐
SAP JVM 8.1 64位是一个专为SAP系统设计的Java虚拟机,它基于Oracle的Java Development Kit (JDK) 进行优化,以满足SAP应用程序的特定需求。SAP JVM旨在提高性能、可靠性和安全性,同时确保与SAP产品的无缝集成。...
JVM是JavaVirtualMachine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一...
SAP JVM 4.1 64位是一个专为SAP系统设计的Java虚拟机,它主要用于运行SAP的应用程序和服务。此版本是为64位操作系统优化的,旨在提供更好的性能和内存管理能力,特别是在处理大数据量和复杂计算场景时。 首先,我们...
"JVM指令手册详细完整版.pdf" 本资源是关于JVM指令的详细手册,涵盖了JVM指令的各种系列命令,包括未归类系列、const系列、push系列、ldc系列、load系列等。每个系列命令都有其特定的功能和用途,下面我们将逐一...
Java虚拟机(JVM)是Java编程语言的核心组成部分,它为Java程序提供了运行环境。《JVM Specification》是一份详细的技术文档,详细阐述了JVM的设计、工作原理以及其与Java程序之间的交互机制。这份规范是Java开发者...
SAP JVM 7.1 64位是一个专为SAP系统设计的Java虚拟机,它主要用于运行SAP的应用程序和服务。这个版本是基于64位架构,这意味着它可以处理更大的内存,更适合处理大规模的企业级数据和复杂计算。下面将详细讨论SAP ...
JVM(Java Virtual Machine,Java虚拟机)是运行所有Java程序的假想计算机,是Java程序的运行环境,负责执行指令、管理数据、内存、寄存器等,是实现Java跨平台特性的关键部分。JVM指令手册详细记录了JVM的所有操作...
Java虚拟机(JVM)是Java程序运行的基础,它提供了内存管理、类加载和执行字节码等功能。本文将深入探讨JVM的主要知识点,包括内存模型、类加载机制、垃圾收集器及其算法、内存调优工具,以及相关配置选项。 1. **...
尚硅谷jvm课件整理ppt
Java虚拟机(JVM)是Java程序运行的基础,它的调优是提高应用程序性能的关键环节。在JVM调优实践中,了解各个运行时数据区的工作原理至关重要。以下是对这些区域的详细解析: 1. **虚拟机栈**:每个线程都有一个...
Java虚拟机(JVM)是Java程序运行的核心组件,它负责解释和执行字节码,为Java应用程序提供了一个跨平台的运行环境。《JAVA8虚拟机(jvm)规范_Chinese version》提供了关于JVM的详细中文指南,对于理解Java程序的运行...
每个使用Java的开发者都知道Java字节码是在JRE中运行,而JVM则是JRE中的核心组成部分,承担分析和执行Java字节码的工作,而Java程序员通常并不需要深入了解JVM运行情况就可以开发出大型应用和类库。尽管如此,如果你...
从零开始学习并掌握Java虚拟机(JVM)的相关知识对于任何希望深入理解Java程序运行机制的开发者来说都是一项重要技能。本篇文章将基于提供的文件标题、描述以及部分链接信息来构建一系列关于JVM的核心知识点。 ### ...
Java虚拟机(JVM)是Java程序运行的核心组件,它负责解释执行字节码指令,为Java应用程序提供了一个跨平台的运行环境。JVM指令集是JVM内部使用的微指令集合,这些指令构成了Java字节码的基础。在《JVM指令手册》中,...