Algorithm:
70: Climbing Stairs (Easy)
167: Two Sum II - Input array is sorted (Easy)
120: Triangle (Medium)
经典动态规划,状态转移方程是自底向上,row[i] = row[i] + min(pre[i] + pre[i+1]),其中状态是底部终点到该点的累积值。注意不能贪心,因为局部最优的路径限制后面选择。
Review:
Medium: Understanding Java Memory Model
Baeldung: Guide to Java String Pool
Baeldung: Native Memory Tracking in JVM
JVM 内存管理相关的几篇文章,第一篇文章有一系列直观的结构图,对不同层次的结构进行展示和简单介绍,后面两篇文章对字符串池和其他非堆内存进行详细解读。一些概念容易混淆,如 Method Area 在内存结构图中不存在,这是因为它是逻辑概念,可以认为就是 Metaspace 或其中一部分。还有一种划分是堆内存和非堆内存,因为堆内存才是 JVM 替程序员进行自动管理的内存(对比 C 语言手动申请的),非堆内存也称为 Native Allocations,用来管理类型元信息、应用代码、JIT 生成代码、内部数据结构等部分。此外还有系统原生内存使用如 JNI 和 NIO 的直接内存,并不是 JVM 内存管理模型中的内容。
Tip:
使用 JCMD 分析 JVM 非堆内存使用
必须开启 XX:NativeMemoryTracking,注意如果使用 openjdk 需要安装 devel 包才有 jcmd、jstack 等工具。
#yum install java-1.8.0-openjdk-devel
java -Xmx128m -Xms128m -XX:NativeMemoryTracking=summary -XX:+UseG1GC -jar hello.jar
进程整体使用内存,RES:241M,SHR:16M,共 257M。
➜ ~ top -p 28697
top - 03:10:14 up 95 days, 9:13, 2 users, load average: 0.00, 0.01, 0.00
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 6.2 us, 0.0 sy, 0.0 ni, 93.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1008352 total, 188084 free, 398360 used, 421908 buff/cache
KiB Swap: 524284 total, 522992 free, 1292 used. 408088 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28697 root 20 0 2239484 241300 16464 S 0.0 23.9 0:24.84 java
jcmd 信息,第一行 Total 是下面所有明细的总和,其中 reserved 是指潜在使用的量(potentially use),committed 是指正在使用的量(using),这里是 277M,其中 Symbol 部分重复计算 10M,减去后依然比上面257M大 10M,暂时无法解释 TODO。
➜ ~ jcmd 28697 VM.native_memory
28697:
Native Memory Tracking:
Total: reserved=1566062KB, committed=283802KB
- Java Heap (reserved=131072KB, committed=131072KB)
(mmap: reserved=131072KB, committed=131072KB)
# Heap 128M = Xmx
- Class (reserved=1090748KB, committed=48008KB)
(classes #8368)
(malloc=1212KB #10492)
(mmap: reserved=1089536KB, committed=46796KB)
# Metaspace 已用 46M,注意总量始终 1G,不是 MaxMetaspaceSize
- Thread (reserved=35066KB, committed=35066KB)
(thread #35)
(stack: reserved=34912KB, committed=34912KB)
(malloc=114KB #201)
(arena=40KB #66)
# Threads stack 对应 Xss 1M,35个线程共35M,总量随着运行分配变化
- Code (reserved=251689KB, committed=12425KB)
(malloc=2089KB #4086)
(mmap: reserved=249600KB, committed=10336KB)
# Code Cache 已用 39M,总量 245M,对应-XX:ReservedCodeCacheSize
- GC (reserved=40430KB, committed=40430KB)
(malloc=2798KB #3878)
(mmap: reserved=37632KB, committed=37632KB)
# GC algorithms,G1 已用 39M,总量随着运行分配变化
- Compiler (reserved=162KB, committed=162KB)
(malloc=31KB #383)
(arena=131KB #5)
- Internal (reserved=2312KB, committed=2312KB)
(malloc=2280KB #11574)
(mmap: reserved=32KB, committed=32KB)
# DirectByteBuffer 等其他未分类部分,已用 2M,总量随着运行分配变化
- Symbol (reserved=12276KB, committed=12276KB)
(malloc=9103KB #88570)
(arena=3173KB #1)
# string tool and constant pool,从 JDK8 起应该在 Heap 中,总量随着运行分配变化
- Native Memory Tracking (reserved=1874KB, committed=1874KB)
(malloc=8KB #91)
(tracking overhead=1866KB)
- Arena Chunk (reserved=178KB, committed=178KB)
(malloc=178KB)
- Unknown (reserved=256KB, committed=0KB)
(mmap: reserved=256KB, committed=0KB)
Share:
Capital One: Go is Boring, And That’s Fantastic!
近期一篇很火热的文章,在 HN 上有300多讨论。作者借助 Go 语言一些特点,深入分析了为什么要依赖简单、可靠、容易理解的技术。主要论据有:
- 性能再次重要起来,因为最近 10 年硬件发展遇到瓶颈
- 尽早发现问题,Go 快速编译以及内置的 Test、Benchmarking、profiling 等工具使其比其他语言生态更容易做到
- 内存很难管理,相比 Rust、Swift 这些半自动的、依然需要深入细节才能用好的方式,Go 有全自动的、性能也足够的自动内存管理。
- 便于 Code Reviews 和 低沟通成本,Go 只有一种风格 go fmt,没有异常、AOP、继承、重载等复杂内容,可以清晰地知道调用什么代码,返回什么值,并且 Go 从发布之初到现在并没有重大语言变化,可以避免熔岩流反模式 lava flow anti-pattern 。
- 最后,语言并不开发中的主要问题,流程、工具、测试、性能、长期维护这些更加重要。而 Go 使用 70 年代的那些设计理念(CSP 等)已经可以很好的解决这些问题。这与其他不断引入新特性的语言、以及一些新引入的语言相比更加乏味,但是使用一些全新的理念、未经充分测试的技术并不是建造可靠桥梁的最佳方法。