我们需要:gmp、mpfr和mpc.还可能需要m4安装工具
编译工具m4 --version查看已经安装的版本,如果过低首先需要升级m4(1.4.18即可)
https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-8.3.0/
https://mirrors.tuna.tsinghua.edu.cn/gnu/gmp/
https://mirrors.tuna.tsinghua.edu.cn/gnu/mpfr/
https://mirrors.tuna.tsinghua.edu.cn/gnu/mpc/
https://mirrors.tuna.tsinghua.edu.cn/gnu/m4/
gcc-8.3.0.tar.gz
mpfr-4.0.2.tar.gz
gmp-6.1.2.tar.xz
mpc-1.0.3.tar.gz

解压,准备依次./configure make make install三部曲.由于各个库之间的依赖关系,安装顺序为m4,gmp,mpfr,mpc
./configure --prefix=/usr/local/gmp
make
make install

./configure --prefix=/usr/local/mpfr --with-gmp=/usr/local/gmp
make
make install

./configure --prefix=/usr/local/mpc --with-gmp=/usr/local/gmp --with-mpfr=/usr/local/mpfr
make
make install

sudo ./configure --prefix=/usr/local/gcc-8.3.0 --with-mpfr=/usr/local/mpfr --with-gmp=/usr/local/gmp --with-mpc=/usr/local/mpc --disable-multilib
make
make install
漫长的编译过程后,在/usr/local/gcc-8.3.0/bin下执行
./gcc -v可以看到版本为8.3以及传递给configure脚本的命令

https://mirrors.ustc.edu.cn/gnu/gdb/
编译gdb并不需要什么依赖,甚至也不需要很高的gcc版本

./configure --prefix=/usr/local/gdb
make
make install

CMake
选择合适版本下载
https://cmake.org/download/
下面是官方教程地址
https://cmake.org/cmake/help/latest/guide/tutorial/index.html

假设我们只有1个源文件ELFAnalyzer.cpp
同目录新建一个CMakeLists.txt如下
cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial ELFAnalyzer.cpp)
执行cmake -G "Unix MakeFile" 即可生成标准的make文件然后make即可得到可执行文件Tutorial
cmake --help可以看到支持的文件格式

gcc生成标准链接库

需要-fPIC选项
则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

假设有source1.cpp
int add(int a,int b){
return a+b;
}
首先生成位置无关目标文件
gcc -fPIC -c source1.cpp
默认生成文件名为source1.o
生成so共享库文件
gcc -shared -o libsource1.so source1.o
使用动态链接库需要-L指定寻找动态链接库文件的路径(可以多个)
g++ main.cpp -L./ -lsource1 -o a.out
这样生成了可执行文件a.out但是如果我们直接./a.out运行它会报找不到动态库文件.
error while loading shared libraries
默认会去/usr/lib下寻找动态链接库文件
ldd a.out可以看这个文件需要哪些库
可以执行
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
来将当前路径加入动态库搜索路径
再执行./a.out即可打印3

名称修饰规则
https://github.com/gchatelet/gcc_cpp_mangling_documentation
https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
https://stackoverflow.com/questions/6921295/dual-emission-of-constructor-symbols
能输出自己的程序.参考文档
https://www.eecs.umich.edu/courses/eecs373/readings/Assembler.pdf
https://www.eecs.umich.edu/courses/eecs373/readings/Linker.pdf

include <stdio.h>

extern const char kCurSourceFile[];
asm(".section .rodata, "a", @progbits\n");
asm("kCurSourceFile:\n");
asm(".incbin "a.cpp"\n");
asm(".byte 0\n");
asm(".previous\n");

int main()
{
printf("%s", kCurSourceFile);
return 0;
}

关于3目运算符的返回值类型
对于cpp,返回值必须有公共的范围(也就是取范围较大的),不能返回指向父类的指针
#include <stdio.h>
#include <stdlib.h>
int f1() { return 2147483647; }
long f2() { return 2147483648; }

class A
{
};
class B : public A
{
};
class C : public A
{
};

int main()
{

srand(time(0));
auto a = rand() % 2 ? B() : C(); //incompatible operand types ('B' and 'C')
A *b = rand() % 2 ? B() : C();   //incompatible operand types ('B' and 'C')
for (int i = 0; i < 30; i++)
{
    int b = rand() % 2 ? f1() : f2();
    printf("%d\n", b);
} //OK.如果f2被执行则打印-2147483648.事实上返回的是long类型

auto b = rand() % 2 ? f1() : f2();
printf("%u\n", sizeof(b)); //打印8说明推断类型为long

return 0;

}

elf文件解析
首先是Elf header(对比DOS header)

typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info /
Elf64_Half e_type; /
Object file type /
Elf64_Half e_machine; /
Architecture /
Elf64_Word e_version; /
Object file version /
Elf64_Addr e_entry; /
Entry point virtual address /
Elf64_Off e_phoff; /
Program header table file offset /
Elf64_Off e_shoff; /
Section header table file offset /
Elf64_Word e_flags; /
Processor-specific flags /
Elf64_Half e_ehsize; /
ELF header size in bytes /
Elf64_Half e_phentsize; /
Program header table entry size /
Elf64_Half e_phnum; /
Program header table entry count /
Elf64_Half e_shentsize; /
Section header table entry size /
Elf64_Half e_shnum; /
Section header table entry count /
Elf64_Half e_shstrndx; /
Section header string table index */
} Elf64_Ehdr;

e_phoff,e_shoff分别记录了program header table和section header table在文件中的偏移量.e_shstrndx是记录了section header table中各个表项名称的那个section的index

通常来说section header table位于文件的末尾处.每个表项结构如下.sh_name表示了它在e_shstrndx这一节中的偏移量.e_shstrndx这一节的内容就是若干个以0结尾的字符串,其中第0个字符串总是空串(只有1个0).这个节名字表自己的名称一般是.shstrtab

typedef struct
{
Elf64_Word sh_name; /* Section name (string tbl index) /
Elf64_Word sh_type; /
Section type /
Elf64_Xword sh_flags; /
Section flags /
Elf64_Addr sh_addr; /
Section virtual addr at execution /
Elf64_Off sh_offset; /
Section file offset /
Elf64_Xword sh_size; /
Section size in bytes /
Elf64_Word sh_link; /
Link to another section /
Elf64_Word sh_info; /
Additional section information /
Elf64_Xword sh_addralign; /
Section alignment /
Elf64_Xword sh_entsize; /
Entry size if section holds table */
} Elf64_Shdr;

sh_type表示了这一节的类型
第0个section的类型永远是SHT_NULL.注意如果elf header中e_shnum这一项为0则实际的section header表项数由第0个section header的sh_size成员给出.
我们主要关心SHT_REL,SHT_RELA(relocation addend)类型的重定位节
SHT_SYMTAB符号表SHT_STRTAB字符串表.
如果某个section实际上是一个表,由于这个section的总大小为sh_size而每个表项的大小为sh_entsize所以总共有
sh_size/sh_entsize个表项.比如重定位表就是这样.如果这个section实际上并不是一个表则sh_entsize=0
对于符号表来说,部分符号有名称,需要一个字符串表保存这些符号名称.这个字符串表的index就由sh_link字段给出.
通常来说,每个重定位节对应于一个要被他重定位的节.假设.text节要被重定位,则记录对应重定位信息的节名称为.rel.text或者.rela.text
sh_addralign字段给出了本节的对齐数,会保证本节在文件中的偏移地址是这个值的倍数.
#define SHT_NULL 0 /* Section header table entry unused /
#define SHT_PROGBITS 1 /
Program data /
#define SHT_SYMTAB 2 /
Symbol table /
#define SHT_STRTAB 3 /
String table /
#define SHT_RELA 4 /
Relocation entries with addends /
#define SHT_HASH 5 /
Symbol hash table /
#define SHT_DYNAMIC 6 /
Dynamic linking information /
#define SHT_NOTE 7 /
Notes /
#define SHT_NOBITS 8 /
Program space with no data (bss) /
#define SHT_REL 9 /
Relocation entries, no addends /
#define SHT_SHLIB 10 /
Reserved /
#define SHT_DYNSYM 11 /
Dynamic linker symbol table /
#define SHT_INIT_ARRAY 14 /
Array of constructors /
#define SHT_FINI_ARRAY 15 /
Array of destructors /
#define SHT_PREINIT_ARRAY 16 /
Array of pre-constructors /
#define SHT_GROUP 17 /
Section group /
#define SHT_SYMTAB_SHNDX 18 /
Extended section indeces /
#define SHT_NUM 19 /
Number of defined types. /
#define SHT_LOOS 0x60000000 /
Start OS-specific. /
#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /
Object attributes. /
#define SHT_GNU_HASH 0x6ffffff6 /
GNU-style hash table. /
#define SHT_GNU_LIBLIST 0x6ffffff7 /
Prelink library list /
#define SHT_CHECKSUM 0x6ffffff8 /
Checksum for DSO content. /
#define SHT_LOSUNW 0x6ffffffa /
Sun-specific low bound. /
#define SHT_SUNW_move 0x6ffffffa
#define SHT_SUNW_COMDAT 0x6ffffffb
#define SHT_SUNW_syminfo 0x6ffffffc
#define SHT_GNU_verdef 0x6ffffffd /
Version definition section. /
#define SHT_GNU_verneed 0x6ffffffe /
Version needs section. /
#define SHT_GNU_versym 0x6fffffff /
Version symbol table. /
#define SHT_HISUNW 0x6fffffff /
Sun-specific high bound. /
#define SHT_HIOS 0x6fffffff /
End OS-specific type /
#define SHT_LOPROC 0x70000000 /
Start of processor-specific /
#define SHT_HIPROC 0x7fffffff /
End of processor-specific /
#define SHT_LOUSER 0x80000000 /
Start of application-specific /
#define SHT_HIUSER 0x8fffffff /
End of application-specific */

/* Legal values for sh_flags (section flags). */

define SHF_WRITE (1 << 0) /* Writable */

define SHF_ALLOC (1 << 1) /* Occupies memory during execution */

define SHF_EXECINSTR (1 << 2) /* Executable */

define SHF_MERGE (1 << 4) /* Might be merged */

define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */

define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */

define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */

define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling

                   required */

define SHF_GROUP (1 << 9) /* Section is member of a group. */

define SHF_TLS (1 << 10) /* Section hold thread-local data. */

define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */

define SHF_MASKOS 0x0ff00000 /* OS-specific. */

define SHF_MASKPROC 0xf0000000 /* Processor-specific */

define SHF_ORDERED (1 << 30) /* Special ordering requirement

                   (Solaris).  */

define SHF_EXCLUDE (1U << 31) /* Section is excluded unless

                   referenced or allocated (Solaris).*/

typedef struct
{
Elf64_Word p_type; /* Segment type /
Elf64_Word p_flags; /
Segment flags /
Elf64_Off p_offset; /
Segment file offset /
Elf64_Addr p_vaddr; /
Segment virtual address /
Elf64_Addr p_paddr; /
Segment physical address /
Elf64_Xword p_filesz; /
Segment size in file /
Elf64_Xword p_memsz; /
Segment size in memory /
Elf64_Xword p_align; /
Segment alignment */
} Elf64_Phdr;

include <stdlib.h>

include <sys/stat.h>

include <unistd.h>

include

include <string.h>

include

include "/usr/include/elf.h"

void print_elf_header_info(const Elf64_Ehdr &elf_header);
void print_section_header_info(const std::vector<elf64_shdr> &Elf64_Shdr_vec, const Elf64_Shdr &name_section, const char *file_buffer, std::vector<int> &symbol_table_index, std::vector<int> &relocation_index, std::vector<int> &relocation_addend_index);
void print_symbol_table_info(const char *file_buffer, Elf64_Off sh_offset, int entry_count, const Elf64_Shdr &string_section_header);
void print_relocation_table_info(const char *file_buffer, Elf64_Off sh_offset, int entry_count);
void print_relocation_addend_table_info(const char *file_buffer, Elf64_Off sh_offset, int entry_count);
void print_relocation_type_info(int type);
void print_program_header_table_info(Elf64_Phdr program_header);</int></int></int></elf64_shdr>

std::string concat_str(const std::vectorstd::string &vec)
{
if (vec.empty())
return "";
std::string s;
for (size_t i = 0; i < vec.size() - 1; i++)
s += vec.at(i) + "|";
s += vec.at(vec.size() - 1);
return s;
}

int main(int argc, const char *argv[])
{
const char *file_path = "/home/tangsong.math/repos/a.out";
if (argc >= 2)
file_path = argv[1];
FILE *fp = fopen(file_path, "r");
if (!fp)
{
printf("file not found\n");
return 0;
}
struct stat file_stat;

memset(&file_stat, 0, sizeof(struct stat));
stat(file_path, &file_stat);
mode_t file_mode = file_stat.st_mode;

std::vector<std::string> file_mode_vec;

if (S_ISLNK(file_mode))
    file_mode_vec.push_back("S_IFLNK");
if (S_ISREG(file_mode))
    file_mode_vec.push_back("S_IFREG");
if (S_ISBLK(file_mode))
    file_mode_vec.push_back("S_IFBLK");
if (S_ISDIR(file_mode))
    file_mode_vec.push_back("S_IFDIR");
if (S_ISFIFO(file_mode))
    file_mode_vec.push_back("S_IFIFO");

if (file_mode & S_ISUID)
    file_mode_vec.push_back("S_ISUID");
if (file_mode & S_ISGID)
    file_mode_vec.push_back("S_ISGID");
if (file_mode & S_ISVTX)
    file_mode_vec.push_back("S_ISVTX");

if (file_mode & S_IRUSR)
    file_mode_vec.push_back("S_IRUSR");
if (file_mode & S_IWUSR)
    file_mode_vec.push_back("S_IWUSR");
if (file_mode & S_IXUSR)
    file_mode_vec.push_back("S_IXUSR");

if (file_mode & S_IRGRP)
    file_mode_vec.push_back("S_IRGRP");
if (file_mode & S_IWGRP)
    file_mode_vec.push_back("S_IWGRP");
if (file_mode & S_IXGRP)
    file_mode_vec.push_back("S_IXGRP");

if (file_mode & S_IROTH)
    file_mode_vec.push_back("S_IROTH");
if (file_mode & S_IWOTH)
    file_mode_vec.push_back("S_IWOTH");
if (file_mode & S_IXOTH)
    file_mode_vec.push_back("S_IXOTH");
printf("file_mode %d %s\n", file_mode, concat_str(file_mode_vec).c_str());

if (!S_ISREG(file_mode))
{
    printf("not a regular file\n");
    return 0;
}
//off_t在macOS是long long
off_t file_size = file_stat.st_size;
printf("file_size = %d\n\n", file_size);
if (file_size < sizeof(Elf64_Ehdr))
{
    printf("not a valid elf64 file\n");
    return 0;
}
char *file_buffer = new char[file_size];

//analyze start
fread(file_buffer, file_size, 1, fp);

Elf64_Ehdr elf_header = *(Elf64_Ehdr *)file_buffer;
print_elf_header_info(elf_header);
//读取section header table
//在此过程中寻找所有的字符串section.也就是sh_type字段=SHT_STRTAB的section header
std::vector<Elf64_Shdr> Elf64_Shdr_vec;
std::vector<Elf64_Shdr> Elf64_SHT_STRTAB_vec;
std::vector<Elf64_Phdr> Elf64_Phdr_vec;
Elf64_Shdr *p_section_header = (Elf64_Shdr *)(file_buffer + elf_header.e_shoff);
Elf64_Phdr *p_program_header = (Elf64_Phdr *)(file_buffer + elf_header.e_phoff);
int section_header_count = elf_header.e_shnum ? elf_header.e_shnum : p_section_header[0].sh_size;
int non_null_section_header_count = 0;
for (int i = 0; i < section_header_count; i++)
{

    Elf64_Shdr_vec.push_back(*p_section_header);
    if (p_section_header->sh_type == SHT_STRTAB)
        Elf64_SHT_STRTAB_vec.push_back(*p_section_header);
    if (p_section_header->sh_type != SHT_NULL)
        non_null_section_header_count++;
    p_section_header++;
}
for (int i = 0; i < elf_header.e_phnum; i++)
{

    Elf64_Phdr_vec.push_back(*p_program_header);
    p_program_header++;
}

Elf64_Shdr section_header_name_section = Elf64_Shdr_vec.at(elf_header.e_shstrndx);

printf("\n\nsection header table count %d\n", section_header_count);
printf("SHT_STRTAB section count %d\n", Elf64_SHT_STRTAB_vec.size());
printf("non null section count %d\n", non_null_section_header_count);

std::vector<int> symbol_table_index;
std::vector<int> relocation_index;
std::vector<int> relocation_addend_index;
print_section_header_info(Elf64_Shdr_vec, section_header_name_section, file_buffer, symbol_table_index, relocation_index, relocation_addend_index);

for (int i = 0; i < symbol_table_index.size(); i++)
{
    printf("symbol table %d info\n", i);
    Elf64_Word string_section_header_index = Elf64_Shdr_vec.at(symbol_table_index[i]).sh_link;

    Elf64_Shdr string_section_header = Elf64_Shdr_vec.at(string_section_header_index);
    int entry_count = Elf64_Shdr_vec.at(symbol_table_index[i]).sh_size / Elf64_Shdr_vec.at(symbol_table_index[i]).sh_entsize;
    print_symbol_table_info(file_buffer, Elf64_Shdr_vec.at(symbol_table_index[i]).sh_offset,
                            entry_count, string_section_header);
}
printf("\n");
printf("relocation section count %d\n", relocation_index.size());
for (int i = 0; i < relocation_index.size(); i++)
{
    printf("relocation table %d info\n", i);

    int entry_count = Elf64_Shdr_vec.at(relocation_index[i]).sh_size / Elf64_Shdr_vec.at(relocation_index[i]).sh_entsize;
    print_relocation_table_info(file_buffer, Elf64_Shdr_vec.at(relocation_index[i]).sh_offset,
                                entry_count);
}
printf("\n");
printf("relocation addend section count %d\n", relocation_addend_index.size());

for (int i = 0; i < relocation_addend_index.size(); i++)
{
    printf("relocation addend table %d info\n", i);

    int entry_count = Elf64_Shdr_vec.at(relocation_addend_index[i]).sh_size / Elf64_Shdr_vec.at(relocation_addend_index[i]).sh_entsize;
    print_relocation_addend_table_info(file_buffer, Elf64_Shdr_vec.at(relocation_addend_index[i]).sh_offset,
                                       entry_count);
}

printf("\n\nprogram header table count %d\n", Elf64_Phdr_vec.size());
for (int i = 0; i < Elf64_Phdr_vec.size(); i++)
{
    printf("[%d. ]", i);
    print_program_header_table_info(Elf64_Phdr_vec.at(i));
}

delete[] file_buffer;

return 0;

}
void print_program_header_table_info(Elf64_Phdr program_header)
{
printf("p_type = %d ", program_header.p_type);
switch (program_header.p_type)
{
case PT_NULL:
printf("PT_NULL ");
break;
case PT_LOAD:
printf("PT_LOAD ");
break;
case PT_DYNAMIC:
printf("PT_DYNAMIC ");
break;
case PT_INTERP:
printf("PT_INTERP ");
break;
case PT_NOTE:
printf("PT_NOTE ");
break;
case PT_SHLIB:
printf("PT_SHLIB ");
break;
case PT_PHDR:
printf("PT_PHDR ");
break;
case PT_TLS:
printf("PT_TLS ");
break;
}
if (PT_LOOS <= program_header.p_type && program_header.p_type <= PT_HIOS)
{
switch (program_header.p_type)
{
case PT_GNU_EH_FRAME:
printf("PT_GNU_EH_FRAME ");
break;
case PT_GNU_STACK:
printf("PT_GNU_STACK ");
break;
case PT_GNU_RELRO:
printf("PT_GNU_RELRO ");
break;
default:
printf("OS-specific");
break;
}
}

printf("\n");

std::vector<std::string> p_flags_vec;
if (program_header.p_flags & PF_X)
    p_flags_vec.push_back("PF_X");
if (program_header.p_flags & PF_W)
    p_flags_vec.push_back("PF_W");
if (program_header.p_flags & PF_R)
    p_flags_vec.push_back("PF_R");
printf("p_flags = %d %s\n", program_header.p_flags, concat_str(p_flags_vec).c_str());

printf("p_offset = %lld\n ", program_header.p_offset);
printf("p_vaddr = %lld \n", program_header.p_vaddr);
printf("p_paddr = %lld \n", program_header.p_paddr);
printf("p_filesz = %lld \n", program_header.p_filesz);
printf("p_memsz = %lld \n", program_header.p_memsz);
printf("p_align = %lld \n\n", program_header.p_align);

}

void print_relocation_table_info(const char *file_buffer, Elf64_Off sh_offset, int entry_count)
{
Elf64_Rel *p_rel = (Elf64_Rel *)(file_buffer + sh_offset);
printf("entry_count= %d\n", entry_count);
for (int i = 0; i < entry_count; i++)
{
printf("[%d. ]", i);
printf("r_offset = %d ", p_rel->r_offset);
printf("r_info = %lld ", p_rel->r_info);
print_relocation_type_info(ELF64_R_TYPE(p_rel->r_info));

    p_rel++;
}

}

void print_relocation_addend_table_info(const char *file_buffer, Elf64_Off sh_offset, int entry_count)
{
Elf64_Rela *p_rela = (Elf64_Rela *)(file_buffer + sh_offset);
printf("entry_count= %d\n", entry_count);
for (int i = 0; i < entry_count; i++)
{
printf("[%d. ]", i);
printf("r_offset = %lld ", p_rela->r_offset);
printf("r_info ELF64_R_SYM=%d ELF64_R_TYPE=%d ", ELF64_R_SYM(p_rela->r_info), ELF64_R_TYPE(p_rela->r_info));
print_relocation_type_info(ELF64_R_TYPE(p_rela->r_info));

    printf("r_addend = %lld \n", p_rela->r_addend);
    p_rela++;
}

}

void print_relocation_type_info(int type)
{

switch (type)
{
case R_386_NONE:
    printf("R_386_NONE ");
    break;
case R_386_32:
    printf("R_386_32 ");
    break;
case R_386_PC32:
    printf("R_386_PC32 ");
    break;
case R_386_GOT32:
    printf("R_386_GOT32 ");
    break;
case R_386_PLT32:
    printf("R_386_PLT32 ");
    break;
case R_386_COPY:
    printf("R_386_COPY ");
    break;
case R_386_GLOB_DAT:
    printf("R_386_GLOB_DAT ");
    break;
case R_386_JMP_SLOT:
    printf("R_386_JMP_SLOT ");
    break;
case R_386_RELATIVE:
    printf("R_386_RELATIVE ");
    break;
case R_386_GOTOFF:
    printf("R_386_GOTOFF ");
    break;
case R_386_GOTPC:
    printf("R_386_GOTPC ");
    break;
}

}

void print_symbol_table_info(const char *file_buffer, Elf64_Off sh_offset, int entry_count, const Elf64_Shdr &string_section_header)
{
Elf64_Sym *p_symbol_table = (Elf64_Sym *)(file_buffer + sh_offset);
printf("entry_count= %d\n", entry_count);
for (int i = 0; i < entry_count; i++)
{
printf("[%d. ]", i);
printf("st_name = %s \n", file_buffer + string_section_header.sh_offset + p_symbol_table->st_name);
printf("st_info = %d ", (int)p_symbol_table->st_info);
switch (ELF64_ST_BIND(p_symbol_table->st_info))
{
case STB_LOCAL:
printf("STB_LOCAL ");
break;
case STB_GLOBAL:
printf("STB_GLOBAL ");
break;
case STB_WEAK:
printf("STB_WEAK ");
break;
}
switch (ELF64_ST_TYPE(p_symbol_table->st_info))
{

    case STT_NOTYPE:
        printf("STT_NOTYPE ");
        break;
    case STT_OBJECT:
        printf("STT_OBJECT ");
        break;
    case STT_FUNC:
        printf("STT_FUNC ");
        break;

    case STT_SECTION:
        printf("STT_SECTION ");
        break;
    case STT_FILE:
        printf("STT_FILE ");
        break;
    case STT_COMMON:
        printf("STT_COMMON ");
        break;

    case STT_TLS:
        printf("STT_TLS ");
        break;
    }

    printf("st_other = %d ", (int)p_symbol_table->st_other);
    printf("st_value = %d ", p_symbol_table->st_value);
    printf("st_size = %lld\n", p_symbol_table->st_size);
    p_symbol_table++;
}

}

void print_section_header_info(const std::vector<elf64_shdr> &Elf64_Shdr_vec, const Elf64_Shdr &section_header_name_section, const char *file_buffer, std::vector<int> &symbol_table_index,
std::vector<int> &relocation_index, std::vector<int> &relocation_addend_index)
{</int></int></int></elf64_shdr>

for (int i = 0; i < Elf64_Shdr_vec.size(); i++)
{
    Elf64_Shdr section_header = Elf64_Shdr_vec.at(i);
    printf("[%d.  ] ", i);
    printf("sh_name = %d %s ", section_header.sh_name, file_buffer + section_header_name_section.sh_offset + section_header.sh_name);
    printf("sh_type = %d ", section_header.sh_type);
    switch (section_header.sh_type)
    {
    case SHT_NULL:
        printf("SHT_NULL\n");
        break;
    case SHT_PROGBITS:
        printf("SHT_PROGBITS\n");
        break;
    case SHT_SYMTAB:
        printf("SHT_SYMTAB\n");
        symbol_table_index.push_back(i);
        break;
    case SHT_STRTAB:
        printf("SHT_STRTAB\n");
        break;
    case SHT_RELA:
        printf("SHT_RELA\n");
        relocation_addend_index.push_back(i);
        break;
    case SHT_HASH:
        printf("SHT_HASH\n");
        break;
    case SHT_DYNAMIC:
        printf("SHT_DYNAMIC\n");
        break;
    case SHT_NOTE:
        printf("SHT_NOTE\n");
        break;
    case SHT_NOBITS:
        printf("SHT_NOBITS\n");
        break;
    case SHT_REL:
        printf("SHT_REL\n");
        relocation_index.push_back(i);
        break;
    case SHT_SHLIB:
        printf("SHT_SHLIB\n");
        break;
    case SHT_DYNSYM:
        printf("SHT_DYNSYM\n");
        break;
    case SHT_INIT_ARRAY:
        printf("SHT_INIT_ARRAY\n");
        break;
    case SHT_FINI_ARRAY:
        printf("SHT_FINI_ARRAY\n");
        break;
    case SHT_PREINIT_ARRAY:
        printf("SHT_PREINIT_ARRAY\n");
        break;
    case SHT_GROUP:
        printf("SHT_GROUP\n");
        break;
    case SHT_SYMTAB_SHNDX:
        printf("SHT_SYMTAB_SHNDX\n");
        break;
    }
    if (SHT_LOOS <= section_header.sh_type && section_header.sh_type <= SHT_HIOS)
        printf("OS-specific type\n");
    //typedef uint64_t Elf64_Xword;
    printf("sh_flags = %lld ", section_header.sh_flags);
    std::vector<std::string> sh_flags_vec;
    if (section_header.sh_flags & SHF_WRITE)
        sh_flags_vec.push_back("SHF_WRITE");
    if (section_header.sh_flags & SHF_ALLOC)
        sh_flags_vec.push_back("SHF_ALLOC");
    if (section_header.sh_flags & SHF_EXECINSTR)
        sh_flags_vec.push_back("SHF_EXECINSTR");
    if (section_header.sh_flags & SHF_MERGE)
        sh_flags_vec.push_back("SHF_MERGE");
    if (section_header.sh_flags & SHF_STRINGS)
        sh_flags_vec.push_back("SHF_STRINGS");
    if (section_header.sh_flags & SHF_INFO_LINK)
        sh_flags_vec.push_back("SHF_INFO_LINK");
    if (section_header.sh_flags & SHF_LINK_ORDER)
        sh_flags_vec.push_back("SHF_LINK_ORDER");
    if (section_header.sh_flags & SHF_OS_NONCONFORMING)
        sh_flags_vec.push_back("SHF_OS_NONCONFORMING");
    if (section_header.sh_flags & SHF_GROUP)
        sh_flags_vec.push_back("SHF_GROUP");
    if (section_header.sh_flags & SHF_TLS)
        sh_flags_vec.push_back("SHF_TLS");
    if (section_header.sh_flags & SHF_COMPRESSED)
        sh_flags_vec.push_back("SHF_COMPRESSED");
    if (section_header.sh_flags & SHF_MASKOS)
        sh_flags_vec.push_back("SHF_MASKOS");
    if (section_header.sh_flags & SHF_MASKPROC)
        sh_flags_vec.push_back("SHF_MASKPROC");
    if (section_header.sh_flags & SHF_ORDERED)
        sh_flags_vec.push_back("SHF_ORDERED");
    if (section_header.sh_flags & SHF_EXCLUDE)
        sh_flags_vec.push_back("SHF_EXCLUDE");
    printf("%s\n", concat_str(sh_flags_vec).c_str());

    printf("sh_addr = %d\n", section_header.sh_addr);
    printf("sh_offset = %lld\n", section_header.sh_offset);
    printf("sh_size = %lld\n", section_header.sh_size);
    printf("sh_link = %d\n", section_header.sh_link);
    printf("sh_info = %d\n", section_header.sh_info);
    printf("sh_addralign = %lld\n", section_header.sh_addralign);
    printf("sh_entsize = %d\n\n", section_header.sh_entsize);
}

}

void print_elf_header_info(const Elf64_Ehdr &elf_header)
{

printf("Elf64_Ehdr info:\n");
//ELF Identification
printf("e_ident[EI_NIDENT=%d] = ", EI_NIDENT);

for (int i = 0; i < EI_NIDENT; i++)
    printf("%x ", elf_header.e_ident[i]);

printf("Magic Number = ");
for (int i = 0; i < 4; i++)
    printf("%x ", elf_header.e_ident[i]);

printf("\nEI_CLASS %d ", (int)elf_header.e_ident[EI_CLASS]);
//EI_CLASS=4
switch (elf_header.e_ident[EI_CLASS])
{
case ELFCLASSNONE:
    printf("ELFCLASSNONE\n");
    break;
case ELFCLASS32:
    printf("ELFCLASS32\n");
    break;
case ELFCLASS64:
    printf("ELFCLASS64\n");
    break;

case ELFCLASSNUM:
    printf("ELFCLASSNUM\n");
    break;

default:
    printf("unspecified EI_CLASS\n");
    break;
}

printf("EI_DATA %d ", (int)elf_header.e_ident[EI_DATA]);
//EI_DATA=5
switch (elf_header.e_ident[EI_DATA])
{
case ELFDATANONE:
    printf("ELFCLASSNONE\n");
    break;
case ELFDATA2LSB:
    printf("ELFDATA2LSB\n");
    break;
case ELFDATA2MSB:
    printf("ELFDATA2MSB\n");
    break;

default:
    printf("unspecified EI_DATA\n");
    break;
}

printf("EI_VERSION %d ", (int)elf_header.e_ident[EI_VERSION]);
//EI_DATA=6
switch (elf_header.e_ident[EI_VERSION])
{
case EV_CURRENT:
    printf("EV_CURRENT\n");
    break;
default:
    printf("unspecified EI_VERSION\n");
    break;
}

printf("EI_OSABI %d ", (int)elf_header.e_ident[EI_OSABI]);
//EI_OSABI=7
switch (elf_header.e_ident[EI_OSABI])
{
case ELFOSABI_NONE:
    printf("ELFOSABI_NONE\n");
    break;
case ELFOSABI_HPUX:
    printf("ELFOSABI_HPUX\n");
    break;
case ELFOSABI_NETBSD:
    printf("ELFOSABI_NETBSD\n");
    break;
case ELFOSABI_GNU:
    printf("ELFOSABI_GNU\n");
    break;
case ELFOSABI_SOLARIS:
    printf("ELFOSABI_SOLARIS\n");
    break;
case ELFOSABI_AIX:
    printf("ELFOSABI_AIX\n");
    break;
case ELFOSABI_IRIX:
    printf("ELFOSABI_IRIX\n");
    break;
case ELFOSABI_FREEBSD:
    printf("ELFOSABI_FREEBSD\n");
    break;
case ELFOSABI_TRU64:
    printf("ELFOSABI_TRU64\n");
    break;
case ELFOSABI_MODESTO:
    printf("ELFOSABI_MODESTO\n");
    break;
case ELFOSABI_OPENBSD:
    printf("ELFOSABI_OPENBSD\n");
    break;
case ELFOSABI_ARM_AEABI:
    printf("ELFOSABI_ARM_AEABI\n");
    break;
case ELFOSABI_ARM:
    printf("ELFOSABI_ARM\n");
    break;
case ELFOSABI_STANDALONE:
    printf("ELFOSABI_STANDALONE\n");
    break;
default:
    printf("unspecified EI_OSABI\n");
    break;
}

printf("EI_ABIVERSION %d ", (int)elf_header.e_ident[EI_ABIVERSION]);
//EI_DATA=6
switch (elf_header.e_ident[EI_ABIVERSION])
{
case 0:
    printf("\n");
    break;
default:
    printf("unspecified EI_ABIVERSION\n");
    break;
}

printf("EI_PAD %d ", (int)elf_header.e_ident[EI_PAD]);
//EI_DATA=6
switch (elf_header.e_ident[EI_PAD])
{
case 0:
    printf("\n");
    break;
default:
    printf("unspecified EI_PAD\n");
    break;
}
//typedef uint16_t Elf64_Half;
Elf64_Half e_type = elf_header.e_type;
printf("e_type %d ", e_type);
switch (e_type)
{

case ET_NONE:
    printf("ET_NONE No file type\n");
    break;

case ET_REL:
    printf("ET_REL Relocatable file\n");
    break;

case ET_DYN:
    printf("ET_DYN Shared object file\n");
    break;

case ET_CORE:
    printf("ET_CORE Core file\n");
    break;
}
if (ET_LOOS <= e_type && e_type <= ET_HIOS)
    printf("OS-specific\n");
if (ET_LOPROC <= e_type && e_type <= ET_HIPROC)
    printf("Processor-specific\n");

Elf64_Half e_machine = elf_header.e_machine;
printf("e_machine %d ", e_machine);
switch (e_machine)
{

case EM_NONE:
    printf("EM_NONE No machine\n");
    break;
case EM_X86_64:
    printf("EM_X86_64 AMD x86-64 architecture\n");
    break;
    //other machine types are omitted.
}
//typedef uint32_t Elf32_Word;
Elf64_Word e_version = elf_header.e_version;

printf("e_version %d ", e_version);
switch (e_version)
{

case EV_NONE:
    printf("EV_NONE Invalid ELF version\n");
    break;

case EV_CURRENT:
    printf("EV_CURRENT Current version\n");
    break;

default:
    printf("unspecified e_version\n");
    break;
}
//typedef uint32_t Elf32_Addr;

Elf32_Addr e_entry = elf_header.e_entry;
printf("e_entry %d Entry point virtual address\n", e_entry);
Elf32_Off e_phoff = elf_header.e_phoff;
printf("e_phoff %d Program header table file offset\n", e_phoff);
Elf32_Off e_shoff = elf_header.e_shoff;
printf("e_shoff %d Section header table file offset\n", e_shoff);
Elf32_Word e_flags = elf_header.e_flags;
printf("e_flags %d Processor-specific flags\n", e_flags);
Elf64_Half e_ehsize = elf_header.e_ehsize;
printf("e_ehsize %d ELF header size in bytes\n", e_ehsize);
Elf64_Half e_phentsize = elf_header.e_phentsize;
printf("e_phentsize %d Program header table entry size\n", e_phentsize);
Elf64_Half e_phnum = elf_header.e_phnum;
printf("e_phnum %d Program header table entry count\n", e_phnum);
Elf64_Half e_shentsize = elf_header.e_shentsize;
printf("e_shentsize %d Section header table entry size\n", e_shentsize);
Elf64_Half e_shnum = elf_header.e_shnum;
printf("e_shnum %d Section header table entry count\n", e_shnum);
Elf64_Half e_shstrndx = elf_header.e_shstrndx;
printf("e_shstrndx %d Section header string table index\n", e_shstrndx);

}

CMake
选择合适版本下载
https://cmake.org/download/
下面是官方教程地址
https://cmake.org/cmake/help/latest/guide/tutorial/index.html

假设我们只有1个源文件ELFAnalyzer.cpp
同目录新建一个CMakeLists.txt如下
cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial ELFAnalyzer.cpp)
执行cmake -G "Unix MakeFile" 即可生成标准的make文件然后make即可得到可执行文件Tutorial
cmake --help可以看到支持的文件格式

gcc生成标准链接库

需要-fPIC选项
则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

假设有source1.cpp
int add(int a,int b){
return a+b;
}
首先生成位置无关目标文件
gcc -fPIC -c source1.cpp
默认生成文件名为source1.o
生成so共享库文件
gcc -shared -o libsource1.so source1.o
使用动态链接库需要-L指定寻找动态链接库文件的路径(可以多个)
g++ main.cpp -L./ -lsource1 -o a.out
这样生成了可执行文件a.out但是如果我们直接./a.out运行它会报找不到动态库文件.
error while loading shared libraries
默认会去/usr/lib下寻找动态链接库文件
ldd a.out可以看这个文件需要哪些库
可以执行
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
来将当前路径加入动态库搜索路径
再执行./a.out即可打印3

关于3目运算符的返回值类型
对于cpp,返回值必须有公共的范围(也就是取范围较大的),不能返回指向父类的指针

include <stdio.h>

include <stdlib.h>

int f1() { return 2147483647; }
long f2() { return 2147483648; }

class A
{
};
class B : public A
{
};
class C : public A
{
};

int main()
{

srand(time(0));
auto a = rand() % 2 ? B() : C(); //incompatible operand types ('B' and 'C')
A *b = rand() % 2 ? B() : C();   //incompatible operand types ('B' and 'C')
for (int i = 0; i < 30; i++)
{
    int b = rand() % 2 ? f1() : f2();
    printf("%d\n", b);
} //OK.如果f2被执行则打印-2147483648.事实上返回的是long类型

auto b = rand() % 2 ? f1() : f2();
printf("%u\n", sizeof(b)); //打印8说明推断类型为long

return 0;

}

Java中可以
import java.util.*;

public class Foo {

public static void main(String[] args) throws Exception {
    Random r = new Random();
    A a = r.nextInt() % 2 == 0 ? new B() : new C();
}

}

class A {
}

class B extends A {
}

class C extends A {
}

  1. 内存占用率高问题排查
    top命令
    图片说明
    统计信息区:
    前五行是当前系统情况整体的统计信息区。下面我们看每一行信息的具体意义。
    第一行,任务队列信息,同 uptime 命令的执行结果,具体参数说明情况如下:
    14:06:23 — 当前系统时间
    up 70 days, 16:44 — 系统已经运行了70天16小时44分钟(在这期间系统没有重启过的吆!)
    2 users — 当前有2个用户登录系统
    load average: 1.15, 1.42, 1.44 — load average后面的三个数分别是1分钟、5分钟、15分钟的负载情况。
    load average数据是每隔5秒钟检查一次活跃的进程数,然后按特定算法计算出的数值。如果这个数除以逻辑CPU的数量,结果高于5的时候就表明系统在超负荷运转了。
    第二行,Tasks — 任务(进程),具体信息说明如下:
    系统现在共有206个进程,其中处于运行中的有1个,205个在休眠(sleep),stoped状态的有0个,zombie状态(僵尸)的有0个。
    第三行,cpu状态信息,具体属性说明如下:
  2. 9%us — 用户空间占用CPU的百分比。
  3. 4% sy — 内核空间占用CPU的百分比。
  4. 0% ni — 改变过优先级的进程占用CPU的百分比
  5. 4% id — 空闲CPU百分比
  6. 0% wa — IO等待占用CPU的百分比
  7. 0% hi — 硬中断(Hardware IRQ)占用CPU的百分比
  8. 2% si — 软中断(Software Interrupts)占用CPU的百分比
    备注:在这里CPU的使用比率和windows概念不同,需要理解linux系统用户空间和内核空间的相关知识!
    第四行,内存状态,具体信息如下:
    32949016k total — 物理内存总量(32GB)
    14411180k used — 使用中的内存总量(14GB)
    18537836k free — 空闲内存总量(18GB)
    169884k buffers — 缓存的内存量 (169M)
    第五行,swap交换分区信息,具体信息说明如下:
    32764556k total — 交换区总量(32GB)
    0k used — 使用的交换区总量(0K)
    32764556k free — 空闲交换区总量(32GB)
    3612636k cached — 缓冲的交换区总量(3.6GB)
    备注:
    第四行中使用中的内存总量(used)指的是现在系统内核控制的内存数,空闲内存总量(free)是内核还未纳入其管控范围的数量。纳入内核管理的内存不见得都在使用中,还包括过去使用过的现在可以被重复利用的内存,内核并不把这些可被重新使用的内存交还到free中去,因此在linux上free内存会越来越少,但不用为此担心。
    如果出于习惯去计算可用内存数,这里有个近似的计算公式:第四行的free + 第四行的buffers + 第五行的cached,按这个公式此台服务器的可用内存:18537836k +169884k +3612636k = 22GB左右。
    对于内存监控,在top里我们要时刻监控第五行swap交换分区的used,如果这个数值在不断的变化,说明内核在不断进行内存和swap的数据交换,这是真正的内存不够用了。
    第六行,空行。
    第七行以下:各进程(任务)的状态监控,项目列信息说明如下:
    PID — 进程id
    USER — 进程所有者
    PR — 进程优先级
    NI — nice值。负值表示高优先级,正值表示低优先级
    VIRT — 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
    RES — 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
    SHR — 共享内存大小,单位kb
    S — 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
    %CPU — 上次更新到现在的CPU时间占用百分比
    %MEM — 进程使用的物理内存百分比
    TIME+ — 进程使用的CPU时间总计,单位1/100秒
    COMMAND — 进程名称(命令名/命令行)
    top按照cpu/内存降序排列
    shift+f可以进入选择,s选中一行然后esc退出选择即可

关于linux的buffer/cache内存

total=used+free+buffers/cached
在 Linux 的内存管理中,这里的buffer 指 Linux 内存的:Buffer cache。这里的 cache 指 Linux 内存中的:Page cache。翻译成中文可以叫做缓冲区缓存和页面缓存。在历史上,它们一个(buffer)被用来当成对 io 设备写的缓存,而另一个(cache)被用来当作对 io 设备的读缓存,这里的 io 设备,主要指的是块设备文件和文件系统上的普通文件。但是现在,它们的意义已经不一样了。在当前的内核中,page cache 顾名思义就是针对内存页的缓存,说白了就是,如果有内存是以 page 进行分配管理的,都可以使用 page cache 作为其缓存来管理使用。当然,不是所有的内存都是以页page进行管理的,也有很多是针对块block进行管理的,这部分内存使用如果要用到 cache 功能,则都集中到 buffer cache 中来使用。(从这个角度出发,是不是 buffer cache 改名叫做 block cache 更好?)然而,也不是所有块block都有固定长度,系统上块的长度主要是根据所使用的块设备决定的,而页长度在 X86 上无论是32位还是64位都是 4k。
明白了这两套缓存系统的区别,就可以理解它们究竟都可以用来做什么了。

什么是 page cache
Page cache 主要用来作为文件系统上的文件数据的缓存来用,尤其是针对当进程对文件有 read/write 操作的时候。如果你仔细想想的话,作为可以映射文件到内存的系统调用:mmap 是不是很自然的也应该用到 page cache?在当前的系统实现里, page cache 也被作为其它文件类型的缓存设备来用,所以事实上 page cache 也负责了大部分的块设备文件的缓存工作。

什么是 buffer cache
Buffer cache 则主要是设计用来在系统对块设备进行读写的时候,对块进行数据缓存的系统来使用。这意味着某些对块的操作会使用 buffer cache 进行缓存,比如我们在格式化文件系统的时候。一般情况下两个缓存系统是一起配合使用的,比如当我们对一个文件进行写操作的时候,page cache 的内容会被改变,而 buffer cache 则可以用来将 page 标记为不同的缓冲区,并记录是哪一个缓冲区被修改了。这样,内核在后续执行脏数据的回写writeback时,就不用将整个 page 写回,而只需要写回修改的部分即可。
块设备也就是存储以“块”为单位数据的设备,比较典型的如磁盘设备、光盘或者u盘
jmap命令
首先用jps命令获取想分析的java进程pid

这里展示的实际上是运行的main class类名
可以用jps -l展示全类名

jmap -histo:live 785801 | more

即可降序排列展示哪些类的对象占用内存过多.
图片说明
[C is a char[]
[S is a short[]
[I is a int[]
[B is a byte[]
[[I is a int[][]

如果报错
Unable to open socket file: target process not responding or HotSpot VM not loaded
可能是由于此进程不是当前用户启动的,可以切换用户再运行此命令
jvm运行时会生成一个目录hsperfdata_USER是启动java进程的用户),在linux中默认是/tmp。目录下会有些pid文件,存放jvm进程信息。
jps、jstack等工具读取/tmp/hsperfdata_$USER下的pid文件获取连接信息。
-heap参数可以打印java内存各部分占用空间信息
我们知道从1.8开始不再有永久代,而是改为Metaspace.从图中我们也可以看到这一点

Heap Configuration
MinHeapFreeRatio = 40

空闲堆空间的最小百分比,计算公式为:HeapFreeRatio =(CurrentFreeHeapSize/CurrentTotalHeapSize) * 100,值的区间为0到100,默认值为 40。如果HeapFreeRatio < MinHeapFreeRatio,则需要进行堆扩容,扩容的时机应该在每次垃圾回收之后。

MaxHeapFreeRatio = 70

空闲堆空间的最大百分比,计算公式为:HeapFreeRatio =(CurrentFreeHeapSize/CurrentTotalHeapSize) * 100,值的区间为0到100,默认值为 70。如果HeapFreeRatio > MaxHeapFreeRatio,则需要进行堆缩容,缩容的时机应该在每次垃圾回收之后。

MaxHeapSize = 4294967296 (4096.0MB)
JVM 堆空间允许的最大值。

NewSize = 1363144 (1.2999954223632812MB)
JVM 新生代堆空间的默认值。

MaxNewSize = 2576351232 (2457.0MB)
JVM 新生代堆空间允许的最大值。

OldSize = 5452592 (5.1999969482421875MB)
JVM 老年代堆空间的默认值。

NewRatio = 2

新生代(2个Survivor区和Eden区 )与老年代(不包括永久区)的堆空间比值,表示新生代:老年代=1:2。

SurvivorRatio = 8

两个Survivor区和Eden区的堆空间比值为 8,表示 S0 : S1 :Eden = 1:1:8。

MetaspaceSize = 21807104 (20.796875MB)
JVM 元空间的默认值。

CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB

JVM 元空间允许的最大值。
下面的解释基于jvm11才有的G1收集器。
G1HeapRegionSize = 1048576 (1.0MB)

在使用 G1 垃圾回收算法时,JVM 会将 Heap 空间分隔为若干个 Region,该参数用来指定每个 Region 空间的大小。

三、Heap Usage
G1 Heap:
regions = 4096
capacity = 4294967296 (4096.0MB)
used = 5242880 (5.0MB)
free = 4289724416 (4091.0MB)
0.1220703125% used

G1 的 Heap 使用情况,该 Heap 包含 4096 个 Region,结合上文每个 RegionSize=1M,因此 Capacity = Regions * RegionSize = 4096 * 1M = 4096M,已使用空间为 5M,空闲空间为 4091M,使用率为 0.12%。

G1 Young Generation:
Eden Space:
regions = 6
capacity = 27262976 (26.0MB)
used = 6291456 (6.0MB)
free = 20971520 (20.0MB)
23.076923076923077% used

G1 的 Eden 区的使用情况,总共使用了 6 个 Region,结合上文每个 RegionSize=1M,因此 Used = Regions * RegionSize = 6 * 1M = 6M,Capacity=26M表名当前 Eden 空间分配了 26 个 Region,使用率为 23%。

G1 Young Generation:
Survivor Space:
regions = 0
capacity = 0 (0.0MB)
used = 0 (0.0MB)
free = 0 (0.0MB)
0.0% used

G1 的 Survivor 区的使用情况,同 Eden区。

G1 Old Generation:
regions = 0
capacity = 241172480 (230.0MB)
used = 0 (0.0MB)
free = 241172480 (230.0MB)
0.0% used

查看jvm dump
jmap -dump:live,format=b,file=heap.hprof <pid>
生成的文件名为heap.hprof
jhat heap.hprof
将会启动一个web server</pid>

访问http://10.227.26.77:7000/
即可查看分析结果
更常用的可能是Eclipse Memory Analyzer(MAT)