$ jdk8-64/java -jar jol-cli.jar internals java.lang.Object # Running 64-bit HotSpot VM. # Using compressed oop with 3-bit shift. # Using compressed klass with 3-bit shift.
Instantiated the sample instance via default constructor.
java.lang.Object object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) 05 00 00 00 # Mark word 4 4 (object header) 00 00 00 00 # Mark word 8 4 (object header) 00 10 00 00 # (not mark word) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
funsimple(): Sequence<Int> = sequence { // sequence builder for (i in1..3) { Thread.sleep(1000) // pretend we are computing it yield(i) // yield next value } }
funsimple(): Flow<Int> = flow { // flow builder for (i in1..3) { delay(100) // pretend we are doing something useful here emit(i) // emit next value } }
funmain() = runBlocking<Unit> { // Launch a concurrent coroutine to check if the main thread is blocked launch { for (k in1..3) { println("I'm not blocked $k") delay(100) } } // Collect the flow simple().collect { value -> println(value) } }
通过flow,我们可以实现异步的数据流。
2、Flow是冷数据流
冷数据流:每次调用collect函数时都会触发执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
funsimple(): Flow<Int> = flow { println("Flow started") for (i in1..3) { delay(100) emit(i) } }
funmain() = runBlocking<Unit> { println("Calling simple function...") val flow = simple() println("Calling collect...") flow.collect { value -> println(value) } println("Calling collect again...") flow.collect { value -> println(value) } }
3、Flow的取消
1 2 3 4 5 6 7 8 9 10 11 12 13 14
funsimple(): Flow<Int> = flow { for (i in1..3) { delay(100) println("Emitting $i") emit(i) } }
funmain() = runBlocking<Unit> { withTimeoutOrNull(250) { // Timeout after 250ms simple().collect { value -> println(value) } } println("Done") }
4、如何构建Flow?
flow{ ... }
flowOf
.asFlow()
5、Flow操作符
5.1 中间操作符
map
filter
transform
take
5.2 终止操作符
collect
toList / toSet
first / single
reduce / fold
5.3 buffer当流的处理速度慢于发射速度时,通过buffer提前缓存可以提高效率:
优化前:耗时1200ms
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
funsimple(): Flow<Int> = flow { for (i in1..3) { delay(100) // pretend we are asynchronously waiting 100 ms emit(i) // emit next value } }
funmain() = runBlocking<Unit> { val time = measureTimeMillis { simple().collect { value -> delay(300) // pretend we are processing it for 300 ms println(value) } } println("Collected in $time ms") }
优化后:耗时1000ms
1 2 3 4 5 6 7 8 9
val time = measureTimeMillis { simple() .buffer() // buffer emissions, don't wait .collect { value -> delay(300) // pretend we are processing it for 300 ms println(value) } } println("Collected in $time ms")
5.4 conflate当生产速度大于消费速度,忽略未来得及处理的值
1 2 3 4 5 6 7 8 9 10 11 12 13
val time = measureTimeMillis { simple() .conflate() // conflate emissions, don't process each one .collect { value -> delay(300) // pretend we are processing it for 300 ms println(value) } } println("Collected in $time ms") //输出: //1 //3 //Collected in 758 ms
5.5 collectLatest 如果消费者很慢,取消它,新值过来时再重新启动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
val time = measureTimeMillis { simple() .collectLatest { value -> // cancel & restart on the latest value println("Collecting $value") delay(300) // pretend we are processing it for 300 ms println("Done $value") } } println("Collected in $time ms") //output: //Collecting 1 //Collecting 2 //Collecting 3 //Done 3 //Collected in 741 ms
5.6 多个flow合并:zip / combine
使用zip操作符
1 2 3 4 5 6 7 8
val nums = (1..3).asFlow() // numbers 1..3 val strs = flowOf("one", "two", "three") // strings nums.zip(strs) { a, b -> "$a -> $b" } // compose a single string .collect { println(it) } // collect and print //output: //1 -> one //2 -> two //3 -> three
当两个flow不同步时:
1 2 3 4 5 6 7 8 9 10 11 12
//速度不同步时,使用zip,到达同步点才输出 val nums = (1..3).asFlow().onEach { delay(300) } // numbers 1..3 every 300 ms val strs = flowOf("one", "two", "three").onEach { delay(400) } // strings every 400 ms val startTime = System.currentTimeMillis() // remember the start time nums.zip(strs) { a, b -> "$a -> $b" } // compose a single string with "zip" .collect { value -> // collect and print println("$value at ${System.currentTimeMillis() - startTime} ms from start") } //output: //1 -> one at 428 ms from start //2 -> two at 828 ms from start //3 -> three at 1230 ms from start
1 2 3 4 5 6 7 8 9 10 11 12 13 14
////速度不同步时,使用combine,有值到达即输出,无视同步 val nums = (1..3).asFlow().onEach { delay(300) } // numbers 1..3 every 300 ms val strs = flowOf("one", "two", "three").onEach { delay(400) } // strings every 400 ms val startTime = System.currentTimeMillis() // remember the start time nums.combine(strs) { a, b -> "$a -> $b" } // compose a single string with "combine" .collect { value -> // collect and print println("$value at ${System.currentTimeMillis() - startTime} ms from start") } //output: //1 -> one at 452 ms from start //2 -> one at 651 ms from start //2 -> two at 854 ms from start //3 -> two at 952 ms from start //3 -> three at 1256 ms from start
typedef struct { Elf32_Word sh_name; /* Section name (string tbl index) */ Elf32_Word sh_type; /* Section type */ Elf32_Word sh_flags; /* Section flags */ Elf32_Addr sh_addr; /* Section virtual addr at execution */ Elf32_Off sh_offset; /* Section file offset */ Elf32_Word sh_size; /* Section size in bytes */ Elf32_Word sh_link; /* Link to another section */ Elf32_Word sh_info; /* Additional section information */ Elf32_Word sh_addralign; /* Section alignment */ Elf32_Word sh_entsize; /* Entry size if section holds table */ } Elf32_Shdr;
Section type
描述
SHT_NULL
This value marks the section header as inactive. It does not have an associated section. Other members of the section header have undefined values.
SHT_PROGBITS
This section holds information defined by the program, whose format and meaning are determined solely by the program.
SHT_SYMTAB
This section holds a symbol table. Typically, SHT_SYMTAB provides symbols for link editing, though it may also be used for dynamic linking. As a complete symbol table, it may contain many symbols unnecessary for dynamic linking. An object file can also contain a SHT_DYNSYM section.
SHT_STRTAB
This section holds a string table. An object file may have multiple string table sections.
SHT_RELA
This section holds relocation entries with explicit addends, such as type Elf32_Rela for the 32-bit class of object files. An object may have multiple relocation sections.
SHT_HASH
This section holds a symbol hash table. An object participating in dynamic linking must contain a symbol hash table. An object file may have only one hash table.
SHT_DYNAMIC
This section holds information for dynamic linking. An object file may have only one dynamic section.
SHT_NOTE
This section holds notes (ElfN_Nhdr).
SHT_NOBITS
A section of this type occupies no space in the file but otherwise resembles SHT_PROGBITS. Although this section contains no bytes, the sh_offset member contains the conceptual file offset.
SHT_REL
This section holds relocation offsets without explicit addends, such as type Elf32_Rel for the 32-bit class of object files. An object file may have multiple relocation sections.
SHT_SHLIB
This section is reserved but has unspecified semantics.
SHT_DYNSYM
This section holds a minimal set of dynamic linking symbols. An object file can also contain a SHT_SYMTAB section.
SHT_LOPROC, SHT_HIPROC
Values in the inclusive range [SHT_LOPROC, SHT_HIPROC] are reserved for processor-specific semantics.
SHT_LOUSER
This value specifies the lower bound of the range of indices reserved for application programs.
SHT_HIUSER
This value specifies the upper bound of the range of indices reserved for application programs. Section types between SHT_LOUSER and SHT_HIUSER may be used by the application, without conflicting with current or future system-defined section types.
ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; }
1.3 图形化表示
1.4 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
publicinterfaceCar{ voiddrive(); }
publicclassBMWCarimplementsCar{
private String name; publicBMWCar(){ name = "宝马"; } @Override publicvoiddrive(){ System.out.println("BMW car drive." + name); } }
CONSTANT_Fieldref_info { u1 tag; u2 class_index;//索引值 u2 name_and_type_index; }
字段的符号引用
10
CONSTANT_Methodref_info
CONSTANT_Methodref_info { u1 tag; u2 class_index;;//索引值 u2 name_and_type_index; }
类中方法的符号引用
11
CONSTANT_InterfaceMethodref
CONSTANT_InterfaceMethodref_info { u1 tag; u2 class_index;;//索引值 u2 name_and_type_index; }
接口中方法的符号引用
12
CONSTANT_NameAndType_info
CONSTANT_NameAndType_info { u1 tag; u2 name_index; u2 descriptor_index; }
接口中方法的符号引用
三、字段的结构
每一个字段用一个 field_info的结构体表示
1 2 3 4 5 6 7
field_info { u2 access_flags; u2 name_index;//指向常量池的index,表示字段名 u2 descriptor_index;//指向常量池的inde,字段的描述符 u2 attributes_count; attribute_info attributes[attributes_count]; }
四、方法的结构
1 2 3 4 5 6 7
method_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count];//Code字节码信息 }
五、属性的结构
1 2 3 4 5
attribute_info { u2 attribute_name_index; u4 attribute_length; u1 info[attribute_length]; }