虚拟机把描述类的数据从 Class 文件加载到内存中,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型,这就是 Java 虚拟机的类加载机制。
类加载的时机,整个生命周期包括:
其中 Verifacation, Preparation, Resolution 三个部分称为 Linking。
四种情况必须对类进行“初始化”。
虚拟机会:
Linking 的第一步,为了确保 Class 文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害到虚拟机自身的安全。
验证字节流是否符合 Class 文件格式规划。
字节码描述的信息进行语义分析,以保证符合 Java 语言规范。
进行数据流和控制流分析。
符号引用验证的目的是确保解析动作能正常执行,如果无法通过符号引用验证,会抛出一个 java.lang.IncompatibleClassChangeError 异常的子类,比如 java.lang.IllegalAccessError, java.lang.NoSuchFieldError, java.lang.NoSuchMethodError 等等。
准备阶段正式为变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。这个阶段中有两个容易产生混淆的概念,这个时候进行内存分配的仅仅包括类变量(被 static 修饰的变量),不包括实例变量。实例变量将会在对象实例化时随着对象一起分配在 Java 堆中。其次初始值“通常”指的是数据类型的零值。
public static int value = 123;
那么变量 value 在准备阶段后,初始化为 0 而不是 123. 但是
public static final int value = 123;
编译时 Javac 将会为 value 生成 ConstantValue 属性,在准备阶段虚拟机就会根据 ConstantValue 设置,将 value 值设置为 123.
虚拟机将常量池内的符号引用替换为直接应用的过程。
到初始化阶段,才真正开始执行类中定义的 Java 程序代码。
初始化阶段是执行类构造器 clinit() 方法的过程。
Java 虚拟机角度,只存在两种不同的类加载器:
工作过程,如果一个类加载器收到类加载的请求,将这个请求委派给父类加载器完成,每一个层次的类加载器都如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈无法完成这个加载请求时,子加载器才会尝试自己去加载。 实现双亲委派的代码都在 java.lang.ClassLoader 的 loadClass() 方法中。
解压和打包 jar 包,使用如下的方式。
unpack
jar xf filename.jar
pack
jar cf filename.jar path/to/dir
将打包好的 jar 包上传到 Nexus
mvn deploy:deploy-file -DgroupId=my.group.id \
-DartifactId=my-artifact-id \
-Dversion=1.0.1 \
-Dpackaging=jar \
-Dfile=realfilename.jar \
-DgeneratePom=true \
-DrepositoryId=my-repo \
-Durl=http://my-nexus-server.com:8081/repository/maven-releases/
记住这里的 repositoryId 一定是 ~/.m2/settings.xml
文件中的 ID, 另外 url 也要区分一下 releases 和 snapshots.
<servers>
<server>
<id>my-repo</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>
记录一下在 Linux 下测试硬盘读写速度的命令和方法。
使用 dd 测试写速度,千万有注意 of
后接的文件必须是一个不存在的文件,否则可能造成数据丢失!
sync; dd if=/dev/zero of=/tmp/tempfile bs=1M count=1024; sync
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 2.55331 s, 421 MB/s
同样的道理,如果要测试一个外部存储,需要知道挂载点,然后用 dd 命令:
sync; dd if=/dev/zero of=/media/user/MyUSB/tempfile bs=1M count=1024; sync
使用 dd 测试读取速度,注意这里的 if
后需要接上一个命令生成的文件:
dd if=/tmp/tempfile of=/dev/null bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.271083 s, 4.0 GB/s
清楚 cache,准确的测试真实的读速度:
sudo /sbin/sysctl -w vm.drop_caches=3
dd if=/tmp/tempfile of=/dev/null bs=1M count=1024
使用 hdparm 也可以对硬盘进行测试。
apt install hdparm
先用 lsblk
或者 fdisk -l
来查看设备信息,一般磁盘都是 /dev/sda
这样。
然后用如下命令测试:
sudo hdparm -Tt /dev/sda
/dev/sda:
Timing cached reads: 31236 MB in 1.99 seconds = 15733.75 MB/sec
Timing buffered disk reads: 504 MB in 3.01 seconds = 167.51 MB/sec
昨天在整理同步工具的时候接触到了 Syncthing,简直秒杀了我现在使用的任何同步工具,所以不得不花一些篇幅来记录一下。
在看到 Syncthing 的介绍时,就非常好奇它的同步原理。也幸亏它的官方文档也有非常详细的 QA
几个比较重要的点:
下载及安装过程不再赘述,官网已经非常详细了。
Syncthing 有个端口需要注意一下
tcp://0.0.0.0:22000
服务监听地址udp://0.0.0.0:21027
本地发现服务端口在 Unix 下在 $HOME/.config/syncthing
下
vi ~/.config/syncthing/config.xml
然后修改本地监听地址从 127.0.0.1 到 0.0.0.0.
如果熟悉 supervisord 可以使用官方提供的文档配置,如果在 Linux 下可以尝试使用 Systemd
sudo systemctl enable syncthing@yourname.service
sudo systemctl start syncthing@yourname.service
记得把 yourname 替换成用户名。
Syncthing 服务启动后端口是 8384.
推荐的理由:
有一种情况是,加入只想要在本地局域网中传输数据,那么可以关闭全局 Discovery 服务器,然后在设置中手动指定某一态服务器的 IP 和 端口,而不是使用默认的 dynamic。这样所有的数据就会在本地传输。
Syncthing 支持文件的版本控制,当从 cluster 同步,删除或者同步一个新版本之后备份之前的老版本。
Syncthing 支持三种工作模式:[^folder]
[^folder]
比较容易理解,但是假如 A 设备设置仅发送,B 设备设置发送和接收,A 是不会同步 B 的更改的!
忽略列表,和 gitignore
类似。每一台设备上的 .stignore
都是分别设置的,不会进行同步。
如果A的.stignore
忽略了 test
,而B没有这样做,实际上会发生这样的事情:
Web页显示的最后更改或者Last Change是指根据【他方的变动】【对自己做修改】的情况和时间。
Web页显示的最后扫描或者Last Scan是指对【己方的目录】最后扫描的时间。
Web 页显示的 Out Of Sync 或者未同步是指尚未接他方推送的变动,如果已收到对方关于变动的通知,但因为下载问题或者.stignore
的设定而未能下载这些变动,就会出现这个情况。
Override Changes Override Changes 或者撤销变动,中文译法有些不准确。出现这个提示的原因通常是设为仅发送的一方(A,master)认为自己的资料是最新的,认为对方(B)推送的变动是应该被撤销的,即使B关于特定资料的修订时间要晚于本地;点这个按钮会强迫B对方撤销自己的变动,以其收到的A的版本为准更改资料。
陆陆续续用过不少同步工具,资料备份,各个设备间同步文件,从商业化的工具到命令行工具,但总还是一直在寻找一款足于满足我所有需求的工具。这里就整理一下,顺便整理一下我自己的思路。不久前就一直在思考一个问题,数字文件的生命有多长,以前看到过一句话,几十年前父母写下的日记如今依然能从旧书柜中翻出,数十年前的胶卷照片依然还很清晰,但往往几年前的网络文章,或者数字照片可能如今随着网络服务的关闭,物理硬盘的损坏而无法恢复。有人尝试使用多地备份,有人尝试云服务备份,却都无法从根本上解决这个问题,当然现在的我依然没有办法完全的解决这个问题。
目前我从两个方面来规避这个问题,一方面物理备份一份,一方面网络存储一份。虽然可以从大部分情况下解决一些问题,不过并不能保证 100 % 数据安全。
中心化的同步工具就像是那个时候的 SVN,使用体验完全依赖于中心服务器,网速,磁盘大小都决定了最后的使用体验。
最早接触到同步工具应该就是 Dropbox 了,PC 上,手机上都是使用 Dropbox 来同步的,并且我的 Dropbox 利用率一直都还是很高。但是 Dropbox 因为网络问题原因,有些时候可能会比较慢。所以一直作为保留项目。
在 Dropbox 之后,也用过 pCloud 不过也并没有深度使用。
之后就是尝试在 VPS 上建了 NextCloud,然后买了 NAS 之后把内容备份到了 NAS 上,并且开始深度使用 NextCloud
不过以上这些工具都有一些问题,比如我都只用来同步一些相对比较小的文件,比如文件,图片,文档等等内容。因为受到同步服务器容量的限制,所以有些文件我会有意识的不同步。
去中心化的服务有很多,这些年陆陆续续也都用过很多。就我个人而言,如果使用命令行,我会用 rsync, 如果要有一个比较友好的界面,我会用 Syncthing。
rsync 之前的文章 已经提到过,很多使用方法那篇文章中也有提及,这里就不赘述了。
unison 没怎么用过,但是 unison 经常被用来和 rsync, syncthing 一起比较,想必也有他的过人之处。
曾经用过很长一段时间,说是去中心化的,但是国内把中心服务的节点屏蔽之后就很难连接上其他地址了,所以后来就放弃了。不过 NAS 上还一直留着,使用起来也非常不错。
如果想要分享只读大文件给很多人,不妨体验一下。
之前也有写过一篇文章 威联通上使用 verySync,但是这个同步工具毕竟还是用的人少,并且还是国产闭源应用,可信度不高。作为 Resilio Sync 的国产代替品使用。
开源,跨平台,Go 语言编写,其他就不用多说了。这可能是这一次整理收获最大的一个工具。
添加 Linux 启动项,可以参考官方的文档,非常详细
这个工具足以代替 Dropbox 完成同步任务,支持增量备份,支持版本管理,各个平台都有完美的解决了同步的问题。
insync 是一个可以将本地文件夹和 Google Drive 同步的工具,收费
GoodSync 又一款同步工具,支持很多平台,不过有些功能需要收费。
I found someone submit a pull-request to redis, which modify the init.d script. The modification make me curious about the init script. So this is the research result.
LSB stand for Linux Standard Base.
LSB-compliant init scripts need to:
[optionally] Log messages using the Init.d functions: log_success_msg, log_failure_msg and log_warning_msg
#!/bin/sh ### BEGIN INIT INFO # Provides: scriptname # Required-Start: $all # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start daemon at boot time # Description: Enable service provided by daemon. ### END INIT INFO
解释:
2 3 4 5
0 1 6
几个虚设项目,以 $
开头
$local_fs
本地文件系统被挂载,用到 /var
目录的启动项都需要依赖此$network
网络被启用$named
名称功能被启用$remote_fs
所有文件系统被挂载,包含 /usr
$syslog
系统记录功能启用$time
系统时间被设定$all
所有项目一般的 daemon 应该依赖 $remote_fs
和 $syslog
,核心模块驱动程序等,需要依赖 $local_fs
在 /etc/init.d
目录下有一个 skeleton
文件,可以以此作为文件的基础来进行编辑。
一个脚本需要提供 start, stop, restart, force-reload, status 这几个动作。
最近整理文档,想起来自己的腾讯云,和 Google 云,好几十 G 的对象存储都空着,虽然腾讯云填了一部分同步的书籍,但是还是没有好好利用起来,然后就突然想起来之前看到过有人自己写了一份网盘同步程序,将对象存储作为同步工具来使用,这么一想确实可以尝试一下,毕竟现在 Dropbox 容量渐渐不够用了,如果能作为一份扩充也倒是不错的选择。所以这里就整理一下目前可用的一些方案,然后再做一下决择。
这是一款 PHP 所写的云盘系统,支持多家对象存储,设计采用 Material Design ,看起来也不错。
又一款用 PHP 所写图片管理系统。
基于 Python 的 OneDrive 网盘目录列表
又一款用来展示 One Drive 列表的项目,PHP
基于 Python 的 onedrive 文件本地化浏览系统,使用 MongoDB 缓存文件
用 Go 实现了一套对象存储的服务端,兼容 AWS S3。
一款在线相册
在调查的过程中,还发现了日本的一个云存储服务,TeraCLOUD,提供 10G 空间,还支持 WebDAV ,果断注册一个。如果你也想注册可以注册完之后,用我的 CODE :NDMSQ
支持 WebDAV ,那么我就可以直接在我的 nemo 文件管理器 中 connect 到这个服务,在 File -> Connect to Server 中选择 Secure WebDAV(HTTPS),然后输入 TeraCLOUD 提供的 WebDAV 地址,以及用户名和密码来登录该服务,既不用多安装一个客户端,也可以非常方便的映射到本地文件管理器中。简单的测试了一下,发现上传速度,在我这里竟然达到了惊人的 800 kB/s
其他桌面版,或者移动客户端,只要支持 WebDAV 协议,那么都可以非常方便的使用该服务。官方也提供了一系列的选择方案。
This post is under the environment of Ubuntu 18.04, this instruction will guide how to install shadowsocks libev both server side and client settings manually. And show the step to configure the simple-obfs.
The source code is in following two repositories:
You can manually build and install yourself. But under Ubuntu 18.04, you can just install like this:
sudo apt install shadowsocks-libev simple-obfs
and the configuration is under /etc/shadowsocks-libev/
. You can manullay modify it and make it work.
If your system is before Ubuntu 18.04, you have to build it from source.
Install shadowsocks-libev via Ubuntu PPA
sudo apt-get install software-properties-common -y
sudo add-apt-repository ppa:max-c-lv/shadowsocks-libev -y
sudo apt-get update
sudo apt install shadowsocks-libev
Install simple-obfs
sudo apt-get install --no-install-recommends build-essential autoconf libtool libssl-dev libpcre3-dev libev-dev asciidoc xmlto automake
git clone https://github.com/shadowsocks/simple-obfs.git
cd simple-obfs
git submodule update --init --recursive
./autogen.sh
./configure && make
sudo make install
Make ~obfs-server~ able to listen on port 443
setcap cap_net_bind_service+ep /usr/local/bin/obfs-server
Server configuration
Add below to ~/etc/shadowsocks-libev/config.json~
{
"server":"0.0.0.0",
"server_port":443,
"local_port":1080,
"password":"password",
"timeout":300,
"method":"chacha20-ietf-poly1305",
"plugin":"obfs-server",
"plugin_opts": "obfs=tls;obfs-host=www.douban.com",
}
Start ~shadowsocks-libev~ server
systemctl enable shadowsocks-libev.service
systemctl start shadowsocks-libev.service
systemctl status shadowsocks-libev.service
Optimizations
Install & enable BBR TCP congestion control
apt install --install-recommends linux-generic-hwe-16.04
apt autoremove
modprobe tcp_bbr
echo "tcp_bbr" >> /etc/modules-load.d/modules.conf
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
sysctl -p
MISC
Add below to ~/etc/sysctl.d/local.conf~
fs.file-max = 51200
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.netdev_max_backlog = 250000
net.core.somaxconn = 4096
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_mem = 25600 51200 102400
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.tcp_mtu_probing = 1
Reboot
reboot
Client configuration
Add below to /usr/local/etc/shadowsocks-libev.json
Note that the ~plugin~ has to be absolute path in order to be able to use ~brew services start shadowsocks-libev~.
{
"server":"SERVER",
"server_port":443,
"local_address": "127.0.0.1",
"local_port":1080,
"password":"PASSWORD",
"timeout":300,
"method":"chacha20-ietf-poly1305",
"workers":8,
"plugin":"/usr/local/bin/obfs-local",
"plugin_opts": "obfs=tls;obfs-host=www.bing.com",
"fast_open":true,
"reuse_port":true
}
When you encouter the high cpu load caused by java application, you may follow these steps to troubleshooting.
identify the PID, use top
or htop
then press P
, sorted by CPU
identify the thread using top -n 1 -H -p PID
, this command will give an output listing all the threads in the selected process
like this:
KiB Mem : 16342620 total, 270500 free, 12773428 used, 3298692 buff/cache
KiB Swap: 7812092 total, 2654116 free, 5157976 used. 1999284 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28958 einverne 20 0 8824828 3.021g 23784 S 30.0 19.4 0:00.00 java
28959 einverne 20 0 8824828 3.021g 23784 S 0.0 19.4 0:00.56 java
28960 einverne 20 0 8824828 3.021g 23784 S 0.0 19.4 0:10.35 GC Thread#0
28961 einverne 20 0 8824828 3.021g 23784 S 0.0 19.4 0:00.06 G1 Main Marker
28962 einverne 20 0 8824828 3.021g 23784 S 0.0 19.4 0:07.24 G1 Conc#0
28963 einverne 20 0 8824828 3.021g 23784 S 0.0 19.4 0:00.42 G1 Refine#0
Here for example, PID 28958 use 30% of CPU.
Then use jstack
to show the stack trace for the PID
jstack PID > jstack.out
Use the above result as example, thread id 28958 is the problem thread. Then convert it to hex value. 28958 -> 711e
Here I provide an easy way to convert decimal to hexadecimal under bash:
printf '%x\n' 28958
# or
echo "obase=16; 28958" | bc
Search the stack trace output for the hex value using the tools you’re familiar with, grep
, less
etc.
less jstack.out
Then you will found the thread details.
vim-abolish 又一款 Tim Pope 大神所制作的插件,这款插件扩展了一条名为 :Subvert
的自定义命令,作用类似于 Vim 内置命令 :substitute
的扩展。
比如说想要将整个文档中的 man 和 dog 两个单词交换,如果用 Vim 原生的替换比较麻烦,而使用该插件则只需要 :%S/{man,dog}/{dog,man}/g
在 GitHub 页面上也有大量的使用方式介绍,这里再提一个官方页面上的用例,比如想要把所有的 facility 替换成 building,那么 facility 有复数, building 也有复数,怎么办
:%S/facilit{y, ies}/building{,s}/g
这个比较好理解,但是 Abolish 还有一个非常贴心的转换,在编程中有驼峰命名,小写字母加下划线命令,假如要将一些变量从小写下划线变成驼峰命名,这个插件提供了一个方法 crc
compute_vm_current_status
将光标移动到该变量名,然后按下 crc
就可以快速将变量命名修改成 camelCase (crc).
同样的
更加详细内容 :help abolish