日期: 2021 年 8 月 11 日

Java 和 Python 并列第二、Julia 下滑,揭晓 RedMonk *新编程语言榜单!

近日,全球知名行业分析公司 RedMonk 发布了 Q3 的编程语言榜单,本排行榜基于 GitHub 和 Stack Overflow 两大社区中使用及讨论的编程语言热度进行排行,真实地反应了开发者对各大编程语言应用的现状,也希望透过此榜单能够为更多的从业者在工具的抉择层面带来一些借鉴。

%title插图%num

RedMonk 编程语言排行榜 TOP 20

通过调查与分析,RedMonk 编程语言排行榜 TOP 20 如下:

%title插图%num

  1. JavaScript
  2. Python
  3. Java
  4. PHP
  5. CSS
  6. C++
  7. C#
  8. TypeScript
  9. Ruby
  10. C
  11. Swift
  12. R
  13. Objective-c
  14. Shell
  15. Scala
  16. Go
  17. PowerShell
  18. Kotlin
  19. Rust
  20. Dart

%title插图%num

值得关注的变化

和上个季度的榜单相比,在本季度中,RedMonk 官方也总结出一些值得关注的重要变化:

  • Java

过去一段时间中,在 Python 迅猛的增速之下,Java 的脚步有所放缓,从原来的第二名下降到了第三位,就在很多从业者担心 Java 的使用率是否会进一步下降时,在本季度中,Java 重新回归,与 Python 并列榜单第二位。

不过,在编程语言层出不穷的发展趋势下,不少从业者似乎并不太看好 Java,甚至定期为企业基础设施的坚定者(Java)撰写墓志铭。但现实来看,Java 屹立不倒自然有其自身的发展优势,它曾作为用于数字电视机顶盒的一种主力编程语言,在不断变化的技术潮流中,仍然可以找到其能够胜任的地方。

这些年来,Java 在这些排名上的表现给人留下深刻印象,而且由于它表现出非凡的适应快速变化环境的能力,因此它是一种难以与之抗衡的语言。

  • TypeScript

TypeScript 在本季度的排名位居第八位,现在该语言面临*大的问题是其是否还能够持续增长甚至超越 C#、C++、PHP 等老牌编程语言?亦或是现在的排名已经到了它的*限?

对此,RedMonk 官方表示,现在一切说不准,但一年前这个时候,TypeScript 在排名所依据的综合得分中落后第 5 名语言 6 分,但这次差距只有两个点。当然,过去的表现也不总是能够代表其未来的发展。

  • Go/Kotlin/Rust

与 TypeScript 一样,Kotlin 和 Rust 在本次排名中都没有变化。一方面,这一现状可能会令该些语言的拥护者失望,但另一方面,它也反映了系统语言新出现的一些现实问题,即 Kotlin 和 Rust 的相对表现,以及 Go 的长期停滞不前会给我们带来一些思考。

多年来,Java 一直面临着强大挑战者的挑战,以争夺企业应用程序首选语言的称号。但是,正如上文所述,Java 并没有在被挑战的过程中受到一定的影响。事实上,与 Go、Kotlin 和 Rust 不同,Java 在排在第三位的两个季度之后,它的份额在此次成功增长。通过自身适应性和企业应用的习惯相结合,Java 仍在企业级应用程序市场中占有很大的份额,这也意味着 Go、Rust、Kotlin 这些挑战者能够带来的影响微乎其微,同时因为这些语言共享 JVM 平台,所以其与 Java 之间的竞争要远小于这些语言内部之间的竞争。

  • Dart

上个季度,RedMonk 在发布编程语言榜单时,曾分析了 Dart 正在逐渐上涨的原因:虽然其语法不如 Kotlin 简洁,但是随着 Flutter 框架的成熟发展,Dart 的未来可期。

如今经过了一个季度的时间,Dart 正如期待的那番,取代了 Perl 的位置成功进入榜单的 TOP 20。在实现这一小成就之后,现在的问题就是 Dart 能否持续保持着 TOP 20 的排名了。当前,排在其前面的 Kotlin 和 Rust 两门语言的受欢迎度要略胜 Dart 一筹,因此,Dart 能否在挑战中站稳自己的脚步,还得看接下来的表现。

  • Julia

不久前,Julia 所在的公司 Julia Computing 刚刚完成了 2400 万美元的 A 轮融资,这笔资金将被用于发展 Julia 生态系统,而 Julia 语言自设计之初也被寄予厚望,正如其开发团队所设想的那番,Julia 将集 Python、C、Ruby、R、Perl 等众多语言之所长:

我们想要一种拥有自由许可的开源语言,同时拥有 C 的速度和 Ruby 的灵活。我们想要一种同像性语言,有像 Lisp 这样真正的宏,也有像 Matlab 这样的浅显熟悉的数学符号。我们想要一门像 Python 一样可用于通用编程,像 R 一样易于统计,像 Perl 一样自然地用于字符串处理,像 Matlab 一样强大的线性代数,像 shell 一样擅长将程序粘合在一起的语言。它简单易学,却能让严苛的黑客为之倾心。我们希望它是交互式的,具备可编译性。

不过,通过调查数据显示,Julia 在竞争愈发激烈的技术圈中,排名有所下滑,一年前 Julia 徘徊于 TOP 20 的边缘位置,位于第 24 位,但在本季度中它跌至第 28 位。值得注意的是,排名越低,语言之间的*对差异变得越小,但是对于一种语言而言,这样的负面表现并不令人鼓舞。

对此,RedMonk 深入分析 Julia 语言下滑的原因时发现,在 Julia 发展过程中,由于其非常注重分析等功能的构建,Julia 经常被开发者列入与 Python、R 等常用统计分析工具的竞争中,其中 Python、R 语言早已在各种实践中证明了自己的受欢迎度与可持续性,此时,新兴 Julia 语言的加入就有些黯然失色了。在此,也希望获得新一轮融资的 Julia 在未来会有亮眼的特性出现。

完整的榜单:

%title插图%num

图 RedMonk Q3 编程语言排行榜

参考来源:

The RedMonk Programming Language Rankings: June 2021

使用MYSQL_BIND 要注意的一个问题

*近遇到一个奇怪的问题,一个无符号32位变量,当我传递值32771的时候,mysql数据库返回了一个错误,说值溢出了。32771,已经超过了65536的一半多,我猜测数据库当成有符号32位整数来处理了,于是查Mysql文档,发现一段这样的描述”you should also indicate whether the variable has the unsigned attribute by setting the is_unsigned member, described later. “于是添加了这个属性的显示指示,问题解决。

mysql中length字符长度函数使用方法

在mysql中length是计算字段的长度一个汉字是算三个字符,一个数字或字母算一个字符了,与char_length是有一点区别,本文章重点介绍*个函数。

mysql里面的length函数是一个用来获取字符串长度的内置函数。具体用法示例如下:

(1)查看某字符串的长度(比如本站网址)

SELECT LENGTH(‘www.111cn.net’);

(2)查询文章表(article)中标题*长的10篇文章

SELECT id,title FROM article ORDER BY LENGTH(title) DESC;

(3)查出用户名长度小于6个字符的用户列表

SELECT * FROM user WHERE LENGTH(username) < 6;

在mysql内置函数里面查看字符串长度的还有一个函数是char_length,这两个函数的区别是:

length: 一个汉字是算三个字符,一个数字或字母算一个字符。

char_length: 不管汉字还是数字或者是字母都算是一个字符。

MYSQL_BIND结构的成员buffer_length与length的区别

*近在搞MySQL的编程,直接使用mysql_query()没有多大的问题。不过为了提高效率,改用了mysql_stmt_prepare(),mysql_stmt_bind()与mysql_stmt_execute()来查询。这样,只要对查询语句解析一次,就可以多次执行,且由于使用二进制来交换数据,不必进行多次转换。如果一切顺利的话,效率应该有很大的提高。

不过,事情没有预想中的那么一帆风顺。在填写了MYSQL_BIND结构并执行mysql_execute()查询后,才发觉结果为空集。其实这些操作都成功执行了(返回值为0),问题到底出在哪里呢?

后来在网上查了一下,发现可以把实际查询的语句的记录输出到LOG文件中。又改了一下程序,并留意了LOG文件中的记录,发现BLOB字段的长度有问题,好像没有变。不过我每次写的buffer_length都不一样啊。

查了一下英文手册才发现buffer_length和length好像不太一样。当length为NULL时,buffer_length可以作为长度来用。不过,改变buffer_length之后必须重新调用mysql_stmt_bind()才会对查询起作用。而length只要改变其所指向的unsigned long,就会在下一次查询起作用,不用重新调用mysql_stmt_bind()。

看来我真的错了。花了半天时间,总算把这个问题弄清楚了。

MYSQL数据优化常用配置参数

常用
*大连接数:
max_connections=2000

默认:max_connections=151

指定MySQL可能的连接数量
#指定MySQL可能的连接数量。当MySQL主线程在很短的时间内得到非常多的连接请求,该参数就起作用,之后主线程花些时间(尽管很短)检查连接并且启动一个新线程。
#back_log参数的值指出在MySQL暂时停止响应新请求之前的短时间内多少个请求可以被存在堆栈中。

back_log=1024

默认:back_log=80

索引块的缓冲区大小
key_buffer_size = 32M
#索引块的缓冲区大小,对MyISAM表性能影响*大的一个参数.决定索引处理的速度,尤其是索引读的速度。默认值是8M,通过检查状态值Key_read_requests
#和Key_reads,可以知道key_buffer_size设置是否合理

默认:key_buffer_size=8M

MySQL执行排序使用的缓冲大小
sort_buffer_size = 16M

#是MySQL执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。
#如果不能,可以尝试增加sort_buffer_size变量的大小。

默认:sort_buffer_size=256K

MYSQL读入缓冲区大小
read_buffer_size = 64M
#是MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。
#如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。

默认:read_buffer_size=64K

Join操作缓存大小
join_buffer_size = 16M
#应用程序经常会出现一些两表(或多表)Join的操作需求,MySQL在完成某些 Join 需求的时候(all/index join),为了减少参与Join的“被驱动表”的
#读取次数以提高性能,需要使用到 Join Buffer 来协助完成 Join操作。当 Join Buffer 太小,MySQL 不会将该 Buffer 存入磁盘文件,
#而是先将Join Buffer中的结果集与需要 Join 的表进行 Join 操作,
#然后清空 Join Buffer 中的数据,继续将剩余的结果集写入此 Buffer 中,如此往复。这势必会造成被驱动表需要被多次读取,成倍增加 IO 访问,降低效率。

默认:join_buffer_size=256K

MySQL的随机读缓冲区大小
read_rnd_buffer_size = 32M
#是MySQL的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySQL会首先扫描一遍该缓冲,以避免磁盘搜索,
#提高查询速度,如果需要排序大量数据,可适当调高该值。但MySQL会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。

默认:read_rnd_buffer_size=256K

缓存排序索引大小
myisam_sort_buffer_size = 256M
#当对MyISAM表执行repair table或创建索引时,用以缓存排序索引;设置太小时可能会遇到” myisam_sort_buffer_size is too small”

myisam_sort_buffer_size=102M

缓存空闲的线程以便不被销毁
thread_cache_size = 384
#thread_cahe_size线程池,线程缓存。用来缓存空闲的线程,以至于不被销毁,如果线程缓存在的空闲线程,需要重新建立新连接,
#则会优先调用线程池中的缓存,很快就能响应连接请求。每建立一个连接,都需要一个线程与之匹配。

默认:thread_cache_size=10

set global max_connections=2000;#设置*大连接数
set global key_buffer_size=32*1024*1024;#设置索引块缓冲区大小
set global sort_buffer_size=16*1024*1024;#MySQL执行排序使用的缓冲大小
set global read_buffer_size=64*1024*1024;#MYSQL读入缓冲区大小
set global read_buffer_size=16*1024*1024;#Join操作缓存大小
set global read_rnd_buffer_size=32*1024*1024;#MySQL的随机读缓冲区大小
set global myisam_sort_buffer_size=256*1024*1024;#缓存排序索引大小
set global thread_cache_size=384;#缓存空闲的线程以便不被销毁

#查询
SHOW GLOBAL VARIABLES LIKE ‘thread_cache_size’
1
2
3
4
5
6
7
8
9
10
11
其他
[client]
#客户端设置,即客户端默认的连接参数
port = 3306
#默认连接端口
socket = /usr/local/mysql/data/mysql.sock
#用于本地连接的socket套接字
default-character-set = utf8mb4
#编码

[mysqld]
#服务端基本设置
port = 3306
#MySQL监听端口
socket = /usr/local/mysql/data/mysql.sock
#为MySQL客户端程序和服务器之间的本地通讯指定一个套接字文件
pid-file = /usr/local/mysql/data/mysql.pid
#pid文件所在目录
basedir = /usr/local/mysql
#使用该目录作为根目录(安装目录)
datadir = /usr/local/mysql/database
#数据文件存放的目录
tmpdir = /usr/local/mysql/data/tmp
#MySQL存放临时文件的目录
character_set_server = utf8mb4
#服务端默认编码(数据库级别)
collation_server = utf8mb4_bin
#服务端默认的比对规则,排序规则
user = root
#MySQL启动用户。如果是root用户就配置root,mysql用户就配置mysql
log-error=/usr/local/mysql/data/error.log
#错误日志配置文件(configure file)
secure-file-priv = null

log_bin_trust_function_creators = 1
#开启了binlog后,必须设置这个值为1.主要是考虑binlog安全
#此变量适用于启用二进制日志记录的情况。它控制是否可以信任存储函数创建者,而不是创建将导致
#要写入二进制日志的不安全事件。如果设置为0(默认值),则不允许用户创建或更改存储函数,除非用户具有
#除创建例程或更改例程特权之外的特权

performance_schema = 0
#性能优化的引擎,默认关闭

#ft_min_word_len = 1
#开启全文索引

#myisam_recover
#自动修复MySQL的myisam表

explicit_defaults_for_timestamp
#明确时间戳默认null方式

event_scheduler
#计划任务(事件调度器)
skip-external-locking
#跳过外部锁定;External-locking用于多进程条件下为MyISAM数据表进行锁定

skip-name-resolve
#跳过客户端域名解析;当新的客户连接mysqld时,mysqld创建一个新的线程来处理请求。该线程先检查是否主机名在主机名缓存中。如果不在,线程试图解析主机名。
#使用这一选项以消除MySQL进行DNS解析的时间。但需要注意,如果开启该选项,则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求!

1.这个bind-address强烈推荐不配置
2.如果要配置bind-address的话,这个localhost不能修改,否则在初始化数据库(执行/opt/cloudera/cm/schema/scm_prepare_database.sh mysql cm cm password)时便会报错
如果配置了localhost的话,那么在CDH的安装页面中,配置连接数据库的主机名称必须为localhost
3.强烈不推荐写bind-address=xxx,那么后面的CDH安装对应的组件时要填写的“数据库主机名称”默认使用主机名。
4.如果/etc/my.cnf中配置了bind-address=localhost 的话,那么在CDH的安装页面中,配置连接数据库的主机名称必须为localhost。
缺点:但是在安装hue时,“数据库主机名称”并无法使用localhost或任何主机名,所以造成无法安装hue
5.不配置 bind-address=localhost 的话,则使用主机名(NDOE1)作为此处的数据库主机名称
#bind-address=localhost
#MySQL绑定IP

skip-slave-start
#为了安全起见,复制环境的数据库还是设置–skip-slave-start参数,防止复制随着mysql启动而自动启动

slave_net_timeout = 30
#在中止读取之前等待来自主/从连接的更多数据的秒数。 MySQL主从复制的时候,
#当Master和Slave之间的网络中断,但是Master和Slave无法察觉的情况下(比如防火墙或者路由问题)。
#Slave会等待slave_net_timeout设置的秒数后,才能认为网络出现故障,然后才会重连并且追赶这段时间主库的数据。
#1.用这三个参数来判断主从是否延迟是不准确的Slave_IO_Running,Slave_SQL_Running,Seconds_Behind_Master.还是用pt-heartbeat吧。
#2.slave_net_timeout不要用默认值,设置一个你能接受的延时时间。

local-infile = 0
#设定是否支持命令load data local infile。如果指定local关键词,则表明支持从客户主机读文件

back_log = 1024
#指定MySQL可能的连接数量。当MySQL主线程在很短的时间内得到非常多的连接请求,该参数就起作用,之后主线程花些时间(尽管很短)检查连接并且启动一个新线程。
#back_log参数的值指出在MySQL暂时停止响应新请求之前的短时间内多少个请求可以被存在堆栈中。

#sql_mode = ‘PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION’

sql_mode = NO_ENGINE_SUBSTITUTION,NO_AUTO_CREATE_USER
#sql_mode,定义了mysql应该支持的sql语法,数据校验等! NO_AUTO_CREATE_USER:禁止GRANT创建密码为空的用户。
#NO_ENGINE_SUBSTITUTION 如果需要的存储引擎被禁用或未编译,可以防止自动替换存储引擎

key_buffer_size = 32M
#索引块的缓冲区大小,对MyISAM表性能影响*大的一个参数.决定索引处理的速度,尤其是索引读的速度。默认值是16M,通过检查状态值Key_read_requests
#和Key_reads,可以知道key_buffer_size设置是否合理

max_allowed_packet = 512M
#一个查询语句包的*大尺寸。消息缓冲区被初始化为net_buffer_length字节,但是可在需要时增加到max_allowed_packet个字节。
#该值太小则会在处理大包时产生错误。如果使用大的BLOB列,必须增加该值。
#这个值来限制server接受的数据包大小。有时候大的插入和更新会受max_allowed_packet 参数限制,导致写入或者更新失败。

thread_stack = 256K
#线程缓存;主要用来存放每一个线程自身的标识信息,如线程id,线程运行时基本信息等等,我们可以通过 thread_stack 参数来设置为每一个线程栈分配多大的内存。

sort_buffer_size = 16M
#是MySQL执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。
#如果不能,可以尝试增加sort_buffer_size变量的大小。

read_buffer_size = 16M
#是MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。
#如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。

join_buffer_size = 16M
#应用程序经常会出现一些两表(或多表)Join的操作需求,MySQL在完成某些 Join 需求的时候(all/index join),为了减少参与Join的“被驱动表”的
#读取次数以提高性能,需要使用到 Join Buffer 来协助完成 Join操作。当 Join Buffer 太小,MySQL 不会将该 Buffer 存入磁盘文件,
#而是先将Join Buffer中的结果集与需要 Join 的表进行 Join 操作,
#然后清空 Join Buffer 中的数据,继续将剩余的结果集写入此 Buffer 中,如此往复。这势必会造成被驱动表需要被多次读取,成倍增加 IO 访问,降低效率。

read_rnd_buffer_size = 32M
#是MySQL的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySQL会首先扫描一遍该缓冲,以避免磁盘搜索,
#提高查询速度,如果需要排序大量数据,可适当调高该值。但MySQL会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。
net_buffer_length = 16K
#通信缓冲区在查询期间被重置到该大小。通常不要改变该参数值,但是如果内存不足,可以将它设置为查询期望的大小。
#(即,客户发出的SQL语句期望的长度。如果语句超过这个长度,缓冲区自动地被扩大,直到max_allowed_packet个字节。)

myisam_sort_buffer_size = 128M
#当对MyISAM表执行repair table或创建索引时,用以缓存排序索引;设置太小时可能会遇到” myisam_sort_buffer_size is too small”

bulk_insert_buffer_size = 32M
#默认8M,当对MyISAM非空表执行insert … select/ insert … values(…),(…)或者load data infile时,使用树状cache缓存数据,每个thread分配一个;
#注:当对MyISAM表load 大文件时,调大bulk_insert_buffer_size/myisam_sort_buffer_size/key_buffer_size会*大提升速度

thread_cache_size = 384
#thread_cahe_size线程池,线程缓存。用来缓存空闲的线程,以至于不被销毁,如果线程缓存在的空闲线程,需要重新建立新连接,
#则会优先调用线程池中的缓存,很快就能响应连接请求。每建立一个连接,都需要一个线程与之匹配。

query_cache_size = 0
#工作原理: 一个SELECT查询在DB中工作后,DB会把该语句缓存下来,当同样的一个SQL再次来到DB里调用时,DB在该表没发生变化的情况下把结果从缓存中返回给Client。
#在数据库写入量或是更新量也比较大的系统,该参数不适合分配过大。而且在高并发,写入量大的系统,建系把该功能禁掉。

query_cache_type = 0
#决定是否缓存查询结果。这个变量有三个取值:0,1,2,分别代表了off、on、demand。

tmp_table_size = 1024M
#它规定了内部内存临时表的*大值,每个线程都要分配。(实际起限制作用的是tmp_table_size和max_heap_table_size的*小值。)
#如果内存临时表超出了限制,MySQL就会自动地把它转化为基于磁盘的MyISAM表,存储在指定的tmpdir目录下

max_heap_table_size = 512M
#独立的内存表所允许的*大容量.# 此选项为了防止意外创建一个超大的内存表导致永尽所有的内存资源.

open_files_limit = 10240
#mysql打开*大文件数

max_connections = 2000
#MySQL无论如何都会保留一个用于管理员(SUPER)登陆的连接,用于管理员连接数据库进行维护操作,即使当前连接数已经达到了max_connections。
#因此MySQL的实际*大可连接数为max_connections+1;
#这个参数实际起作用的*大值(实际*大可连接数)为16384,即该参数*大值不能超过16384,即使超过也以16384为准;
#增加max_connections参数的值,不会占用太多系统资源。系统资源(CPU、内存)的占用主要取决于查询的密度、效率等;
#该参数设置过小的*明显特征是出现”Too many connections”错误;

max-user-connections = 0
#用来限制用户资源的,0不限制;对整个服务器的用户限制

max_connect_errors = 100000
#max_connect_errors是一个MySQL中与安全有关的计数器值,它负责阻止过多尝试失败的客户端以防止暴力破解密码的情况。max_connect_errors的值与性能并无太大关系。
#当此值设置为10时,意味着如果某一客户端尝试连接此MySQL服务器,但是失败(如密码错误等等)10次,则MySQL会无条件强制阻止此客户端连接。

table_open_cache = 5120
#表描述符缓存大小,可减少文件打开/关闭次数;

interactive_timeout = 86400
#interactive_time – 指的是mysql在关闭一个交互的连接之前所要等待的秒数(交互连接如mysql gui tool中的连接
wait_timeout = 86400
#wait_timeout – 指的是MySQL在关闭一个非交互的连接之前所要等待的秒数

binlog_cache_size = 16M
#二进制日志缓冲大小
#我们知道InnoDB存储引擎是支持事务的,实现事务需要依赖于日志技术,为了性能,日志编码采用二进制格式。那么,我们如何记日志呢?有日志的时候,就直接写磁盘?
#可是磁盘的效率是很低的,如果你用过Nginx,,一般Nginx输出access log都是要缓冲输出的。因此,记录二进制日志的时候,我们是否也需要考虑Cache呢?
#答案是肯定的,但是Cache不是直接持久化,于是面临安全性的问题——因为系统宕机时,Cache中可能有残余的数据没来得及写入磁盘。因此,Cache要权衡,要恰到好处:
#既减少磁盘I/O,满足性能要求;又保证Cache无残留,及时持久化,满足安全要求。

slow_query_log = true
#开启慢查询
slow_query_log_file = /usr/local/mysql/data/slow_query_log.log
#慢查询地址
long_query_time = 1
#超过的时间为1s;MySQL能够记录执行时间超过参数 long_query_time 设置值的SQL语句,默认是不记录的。

log-slow-admin-statements
log-queries-not-using-indexes
#记录管理语句和没有使用index的查询记录

主从复制配置 *****************************************************
*** Replication related settings ***
binlog_format = ROW
#在复制方面的改进就是引进了新的复制技术:基于行的复制。简言之,这种新技术就是关注表中发生变化的记录,而非以前的照抄 binlog 模式。
#从 MySQL 5.1.12 开始,可以用以下三种模式来实现:基于SQL语句的复制(statement-based replication, SBR),基于行的复制(row-based replication, RBR),混合模式复制(mixed-based replication, MBR)。相应地,binlog的格式也有三种:STATEMENT,ROW,MIXED。MBR 模式中,SBR 模式是默认的。

#max_binlog_cache_size = 102400

为每个session *大可分配的内存,在事务过程中用来存储二进制日志的缓存。
log-bin = /usr/local/mysql/data/binlog/mysql-bin
#开启二进制日志功能,binlog数据位置
log-bin-index = /usr/local/mysql/data/binlog/mysql-bin.index
relay-log = /usr/local/mysql/data/relay/mysql-relay-bin
#relay-log日志记录的是从服务器I/O线程将主服务器的二进制日志读取过来记录到从服务器本地文件,
#然后SQL线程会读取relay-log日志的内容并应用到从服务器

relay-log-index = /usr/local/mysql/data/relay/mysql-relay-bin.index
#binlog传到备机被写道relaylog里,备机的slave sql线程从relaylog里读取然后应用到本地。

主要配置**
主服务器配置
server-id = 1
#服务端ID,用来高可用时做区分
#binlog-ignore-db = mysql
#binlog-ignore-db = sys
#binlog-ignore-db = binlog
#binlog-ignore-db = relay
#binlog-ignore-db = tmp
#binlog-ignore-db = test
#binlog-ignore-db = information_schema
#binlog-ignore-db = performance_schema

不同步哪些数据库
#binlog-do-db = game

只同步哪些数据库,除此之外,其他不同步
从服务器配置
#server-id = 2
#服务端ID,用来高可用时做区分
#replicate-ignore-db = mysql
#replicate-ignore-db = sys
#replicate-ignore-db = relay
#replicate-ignore-db = tmp
#replicate-ignore-db = test
#replicate-ignore-db = information_schema
#replicate-ignore-db = performance_schema

不同步哪些数据库
#replicate-do-db = game

只同步哪些数据库,除此之外,其他不同步
主要配置**
log_slave_updates = 1
#log_slave_updates是将从服务器从主服务器收到的更新记入到从服务器自己的二进制日志文件中。
expire-logs-days = 15
#二进制日志自动删除的天数。默认值为0,表示“没有自动删除”。启动时和二进制日志循环时可能删除。
max_binlog_size = 128M
#如果二进制日志写入的内容超出给定值,日志就会发生滚动。你不能将该变量设置为大于1GB或小于4096字节。 默认值是1GB。

#replicate-wild-ignore-table = mysql.%
#replicate-wild-ignore-table参数能同步所有跨数据库的更新,比如replicate-do-db或者replicate-ignore-db不会同步类似
#replicate-wild-do-table = db_name.%
#设定需要复制的Table

#slave-skip-errors = 1062,1053,1146
#复制时跳过一些错误;不要胡乱使用这些跳过错误的参数,除非你非常确定你在做什么。当你使用这些参数时候,MYSQL会忽略那些错误,
#这样会导致你的主从服务器数据不一致。

auto_increment_offset = 1
auto_increment_increment = 2
#这两个参数一般用在主主同步中,用来错开自增值, 防止键值冲突

relay_log_info_repository = TABLE
#将中继日志的信息写入表:mysql.slave_realy_log_info
master_info_repository = TABLE
#将master的连接信息写入表:mysql.salve_master_info
relay_log_recovery = on
#中继日志自我修复;当slave从库宕机后,假如relay-log损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的relay-log,
#并且重新从master上获取日志,这样就保证了relay-log的完整性

主从复制配置结束 *****************************************************
*** innodb setting ***
innodb_buffer_pool_size = 128M
#InnoDB 用来高速缓冲数据和索引内存缓冲大小。 更大的设置可以使访问数据时减少磁盘 I/O。

innodb_data_file_path = ibdata1:10M:autoextend
#单独指定数据文件的路径与大小

innodb_flush_log_at_trx_commit = 2
#每次commit 日志缓存中的数据刷到磁盘中。通常设置为 1,意味着在事务提交前日志已被写入磁盘, 事务可以运行更长以及服务崩溃后的修复能力。
#如果你愿意减弱这个安全,或你运行的是比较小的事务处理,可以将它设置为 0 ,以减少写日志文件的磁盘 I/O。这个选项默认设置为 0。

#sync_binlog = 1000
#sync_binlog=n,当每进行n次事务提交之后,MySQL将进行一次fsync之类的磁盘同步指令来将binlog_cache中的数据强制写入磁盘。

innodb_read_io_threads = 8
innodb_write_io_threads = 8
#对于多核的CPU机器,可以修改innodb_read_io_threads和innodb_write_io_threads来增加IO线程,来充分利用多核的性能
innodb_open_files = 1000
#限制Innodb能打开的表的数量
innodb_purge_threads = 1
#开始碎片回收线程。这个应该能让碎片回收得更及时而且不影响其他线程的操作

innodb_log_buffer_size = 8M
#InnoDB 将日志写入日志磁盘文件前的缓冲大小。理想值为 1M 至 8M。大的日志缓冲允许事务运行时不需要将日志保存入磁盘而只到事务被提交(commit)。
#因此,如果有大的事务处理,设置大的日志缓冲可以减少磁盘I/O。

innodb_log_file_size = 128M
#日志组中的每个日志文件的大小(单位 MB)。如果 n 是日志组中日志文件的数目,那么理想的数值为 1M 至下面设置的缓冲池(buffer pool)大小的 1/n。较大的值,
#可以减少刷新缓冲池的次数,从而减少磁盘 I/O。但是大的日志文件意味着在崩溃时需要更长的时间来恢复数据。

innodb_log_files_in_group = 3
#指定有三个日志组

#innodb_lock_wait_timeout = 120
#在回滚(rooled back)之前,InnoDB 事务将等待超时的时间(单位 秒)

innodb_max_dirty_pages_pct = 75
#innodb_max_dirty_pages_pct作用:控制Innodb的脏页在缓冲中在那个百分比之下,值在范围1-100,默认为90.这个参数的另一个用处:
#当Innodb的内存分配过大,致使swap占用严重时,可以适当的减小调整这个值,使达到swap空间释放出来。建义:这个值*大在90%,*小在15%。
#太大,缓存中每次更新需要致换数据页太多,太小,放的数据页太小,更新操作太慢。

innodb_buffer_pool_instances = 4
#innodb_buffer_pool_size 一致 可以开启多个内存缓冲池,把需要缓冲的数据hash到不同的缓冲池中,这样可以并行的内存读写。

innodb_io_capacity = 500
#这个参数据控制Innodb checkpoint时的IO能力

innodb_file_per_table = 1
#作用:使每个Innodb的表,有自已独立的表空间。如删除文件后可以回收那部分空间。
#分配原则:只有使用不使用。但DB还需要有一个公共的表空间。

innodb_change_buffering = inserts
#当更新/插入的非聚集索引的数据所对应的页不在内存中时(对非聚集索引的更新操作通常会带来随机IO),会将其放到一个insert buffer中, #当随后页面被读到内存中时,会将这些变化的记录merge到页中。当服务器比较空闲时,后台线程也会做merge操作

innodb_adaptive_flushing = 1
#该值影响每秒刷新脏页的操作,开启此配置后,刷新脏页会通过判断产生重做日志的速度来判断*合适的刷新脏页的数量;

transaction-isolation = READ-COMMITTED
#数据库事务隔离级别 ,读取提交内容

innodb_flush_method = fsync
#innodb_flush_method这个参数控制着innodb数据文件及redo log的打开、刷写模式
#InnoDB使用O_DIRECT模式打开数据文件,用fsync()函数去更新日志和数据文件。

#innodb_use_sys_malloc = 1
#默认设置值为1.设置为0:表示Innodb使用自带的内存分配程序;设置为1:表示InnoDB使用操作系统的内存分配程序。

[mysqldump]
quick
#它强制 mysqldump 从服务器查询取得记录直接输出而不是取得所有记录后将它们缓存到内存中

max_allowed_packet = 512M
#限制server接受的数据包大小;指代mysql服务器端和客户端在一次传送数据包的过程当中数据包的大小
net_buffer_length = 16384
#TCP/IP和套接字通信缓冲区大小,创建长度达net_buffer_length的行

[mysql]
auto-rehash
#auto-rehash是自动补全的意思

[isamchk]
#isamchk数据检测恢复工具
key_buffer = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M

[myisamchk]
#使用myisamchk实用程序来获得有关你的数据库桌表的信息、检查和修复他们或优化他们
key_buffer = 256M
sort_buffer_size = 256M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout
#mysqlhotcopy使用lock tables、flush tables和cp或scp来快速备份数据库.它是备份数据库或单个表*快的途径,完全属于物理备份,但只能用于备份MyISAM存储引擎和运行在数据库目录所在的机器上.
#与mysqldump备份不同,mysqldump属于逻辑备份,备份时是执行的sql语句.使用mysqlhotcopy命令前需要要安装相应的软件依赖包.

Mysql dump一个小功能描述:参数net-buffer-length的使用

一:转载总结说明
数据备份、特别是大表数据备份时,这个参数很有用处

用处一:比如设置成 –net-buffer-length=10m ,那么一旦你使用到还原时,你的数据一次commit提交是默认1m 提交时的10倍速度

用户二:比如设置成 –net-buffer-length=10m ,小表估计就是一个insert就完事了,导入时效率会很高。当你备份文件有5G 10G了,那个时候这些参数非常有用
具体的配置使用参考:

Windows版本

D:
cd D:\mmxp\mysql\bin
set “Ymd=%date:~,4%%date:~5,2%%date:~8,2%”
mysqldump –default-character-set=utf8 –net-buffer-length=10m –ignore-table=yn.gov_price_category_detail –skip-lock-tables yn> D:\zcsjw\backup\yn\yn_%Ymd%.sql
“C:\Program Files\7-Zip\7z.exe” a “D:\zcsjw\backup\yn\yn_%Ymd%.sql.zip” “D:\zcsjw\backup\yn\yn_%Ymd%.sql”
Windows使用请参考:《Windows系统Mysql数据库备份》

Linux版本

#!/bin/bash
# 需要的话,自己改这里哦
#db_user=’root’
#db_password=`cat /data/www/mysql_password`
db_name=’guides’
backup_dir=’/data/backup/mysql/’
current_time=$(date +’%Y-%m-%d_%H%M%S’)
filepath=$backup_dir$current_time’.sql.gz’
#此处没有使用 $db_password $db_user, 已经写入到配置文件中
echo ‘开始导出数据库…’
mysqldump –defaults-extra-file=/data/backup/my_mysql.cnf $db_name –net-buffer-length=10m | gzip > $filepath
echo ‘导出成功,文件名为: ‘$filepath
Linux使用请参考:《CentOS7 MySQL定时自动备份实现》

注意:备份数据做恢复时,务必将你的数据库配置设置很大

#设置在网络传输中一次消息传输量的*大值 大备份文件大于1G以上
max_allowed_packet=1G
参考:《dump备份出来的还原回去很慢》

二:转载正文
有大师说mysqldump的net-buffer-length这个参数是个鸡肋,对与性能提升不是很大.之前也就没关注过.偶然一次测试.碰到了.就研究了下..其实还是很有用的(对于我们这种菜鸟来说).
下面结合实例讲讲:

讲net-buffer-length之前,先讲另外一个mysqldump的参数–extended-insert
这个参数的意思就是是否开启合并insert(默认是开启的,不想开启直接加skip-extended-insert).用白话讲就是用mysqldump导出生成的insert数据合并成一条,如果不开启就是一条数据一个insert.

开启后导出的格式类似这样: insert into table_name values (xx,xx,xx),(xx,xx,xx),(xx,xx,xx)….
关闭后导出的格式类似这样: insert into table_name values (xx,xx,xx);
insert into table_name values (xx,xx,xx);
insert into table_name values (xx,xx,xx);
.
ok,这个参数应该解释清楚了吧.理想是很丰满的,但现实却是很骨感的.
现实情况是开启了extended-insert参数,如果数据超过1M,也会生成多个insert

[root@testdb3 ~]#/home/mysql3310/bin/mysqldump -S /tmp/mysql3310.sock –databases bigdata –tables t1 >t1.sql
[root@testdb3 ~]# cat t1.sql |grep INSERT |wc -l
125

这就引入net-buffer-length这个参数了
mysqldump(5.7.5以后,官方建议使用mysqlpump)的net-buffer-length 官方的解释就是通信时缓存数据的大小.*小4k,*大16M,默认是1M.
大家都知道.msyqldump导出的数据就包括两部分,一部分是DDL(包含建表,建存储,建视图等sql语句),另一部分就是insert了,所有的数据都是生成insert了,所以insert这部分才是mysqldump的*大部分.

结合上面说到的情况.启用extended-insert,理论上应该一个表只生成一个insert,但如果一个insert的数据超过1M(默认值),就会生成第二个insert,如果在超过1M,就生成第三个insert,以此类推,直到数据全部导完.
下面结合实例来看:

[root@testdb3 ~]#/home/mysql3310/bin/mysqldump -S /tmp/mysql3310.sock –databases bigdata –tables t1 >t1.sql
[root@testdb3 ~]# cat t1.sql |grep INSERT |wc -l
125
[root@testdb3 ~]# sed -n ’99p’ t1.sql >t2.sql
[root@testdb3 ~]# ls -al t2.sql
-rw-r–r–. 1 root root 1042300 Jan 19 10:44 t2.sql

可以看到一个insert就差不多是1M
现在加上net-buffer-length 在来测试:

[root@testdb3 ~]# /home/mysql3310/bin/mysqldump -S /tmp/mysql3310.sock –databases bigdata –tables t1 –net-buffer-length=5000000 >t3.sql
[root@testdb3 ~]# sed -n ‘100p’ t3.sql >t4.sql
[root@testdb3 ~]# ls -al t4.sql
-rw-r–r–. 1 root root 4979542 Jan 19 10:47 t4.sql
设置了差不多5M,看到一条insert就差不多5M的大小了
*大值是16M

[root@testdb3 ~]# /home/mysql3310/bin/mysqldump -S /tmp/mysql3310.sock –databases bigdata –tables t1 –net-buffer-length=25000000 >t5.sql
[root@testdb3 ~]# sed -n ‘100p’ t5.sql >t6.sql
[root@testdb3 ~]# ls -al t6.sql
-rw-r–r–. 1 root root 16712034 Jan 19 10:59 t6.sql

设置了25M,但一个insert还是只有16M.

在来看看导入,导入就是按导出的时候有多少个insert就会有多少个事务(前提是autocommit是开启的);
所以我们在source的时候就会开到类似下面的提示:

Query OK, 4053 rows affected (0.16 sec)
Records: 4053 Duplicates: 0 Warnings: 0

Query OK, 4053 rows affected (0.51 sec)
Records: 4053 Duplicates: 0 Warnings: 0

Query OK, 4053 rows affected (0.16 sec)
Records: 4053 Duplicates: 0 Warnings: 0

Query OK, 4053 rows affected (0.16 sec)
Records: 4053 Duplicates: 0 Warnings: 0

Query OK, 4053 rows affected (0.16 sec)
Records: 4053 Duplicates: 0 Warnings: 0
这是因为导出的时候默认是1M,刚好4053行就是1M,所以会有这样的提示,如果不是1M,就会有如下的提示:

Query OK, 19364 rows affected (0.74 sec)
Records: 19364 Duplicates: 0 Warnings: 0

Query OK, 19363 rows affected (0.75 sec)
Records: 19363 Duplicates: 0 Warnings: 0

Query OK, 19363 rows affected (0.75 sec)
Records: 19363 Duplicates: 0 Warnings: 0

Query OK, 19363 rows affected (0.75 sec)
Records: 19363 Duplicates: 0 Warnings: 0

Query OK, 19364 rows affected (0.74 sec)
Records: 19364 Duplicates: 0 Warnings: 0

这里设置的是5M,就是差不多19364行.

这两个例子都是同样的表结构和数据.
在导入的时候还涉及另外一个参数max_allowed_packet,如果这个值设置过低,会导致数据无法导入的.如下:

mysql> set global max_allowed_packet=1048576;

mysql> show variables like ‘max%’;
+—————————-+———————-+
| Variable_name | Value |
+—————————-+———————-+
| max_allowed_packet | 1048576 |

mysql> source t4.sql;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect…
Connection id: 18
Current database: tt2

ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect…
Connection id: 19
Current database: tt2

ERROR 2006 (HY000): MySQL server has gone away
mysql> source t2.sql;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect…
Connection id: 20
Current database: tt2

Query OK, 4053 rows affected (0.51 sec)
Records: 4053 Duplicates: 0 Warnings: 0

max_allowed_packet设置成了1M,t4.sql是之前的5M的sql,就会导入失败.在看看错误日志:
2017-01-19T13:48:09.975902+08:00 5 [Note] Aborted connection 5 to db: ‘tt2’ user: ‘root’ host: ‘localhost’ (Got a packet bigger than ‘max_allowed_packet’ bytes)

就会有提示的.. 这里就顺带提一下…

好了.到这基本上就清楚了net-buffer-length的功能了.有的人说net-buffer-length对性能提升效果不大.我没去做性能测试,从理论上讲肯定是有所提升的.
首先,导出的性能肯定有所提升.每1M就要分段,和16M在分段,如果是大数据(具体多大,以G为单位吧)导出,肯定会有所提升,如果数据小,当然就看不出啥效果了.
其次,导入.导入的时候,如果1M就要提交一个事务,和16M在提交一个事务,如果磁盘够快,肯定性能和时间是会节省很多的.

具体就不去做性能测试了.因为毕竟只是个小功能,对于有需求的就了解下,没需求就飘过吧……

Android优化—Google 发布 Android 性能优化典范

2015年伊始,Google发布了关于 Android性能优化典范的专题, 一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App。课程专题不仅仅介绍了Android系统中有关性能问题的底层工作原理,同时也介绍了如何通过工具来找出性能问题以及提升性能的建议。主要从三个 方面展开,Android的渲染机制,内存与GC,电量优化。下面是对这些问题和建议的总结梳理。

0)Render Performance

大多数用户感知到的卡顿等性能问题的*主要根源都是因为渲染性能。从设计师的角度,他们希望App能够有更多的动画,图片等时尚元素来实现流畅的用 户体验。但是Android系统很有可能无法及时完成那些复杂的界面渲染操作。Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染, 如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。

Android性能优化典范

如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面。

Android性能优化典范

用户容易在UI执行动画或者滑动ListView的时候感知到卡顿不流畅,是因为这里的操作相对复杂,容易发生丢帧的现象,从而感觉卡顿。有很多原 因可以导致丢帧,也许是因为你的layout太过复杂,无法在16ms内完成渲染,有可能是因为你的UI上有层叠太多的绘制单元,还有可能是因为动画执行 的次数过多。这些都会导致CPU或者GPU负载过重。

我们可以通过一些工具来定位问题,比如可以使用HierarchyViewer来查找Activity中的布局是否过于复杂,也可以使用手机设置里 面的开发者选项,打开Show GPU Overdraw等选项进行观察。你还可以使用TraceView来观察CPU的执行情况,更加快捷的找到性能瓶颈。

1)Understanding Overdraw

Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次。这就浪费大量的CPU以及GPU资源。

Android性能优化典范

当设计上追求更华丽的视觉效果的时候,我们就容易陷入采用越来越多的层叠组件来实现这种视觉效果的怪圈。这很容易导致大量的性能问题,为了获得*佳的性能,我们必须尽量减少Overdraw的情况发生。

幸运的是,我们可以通过手机设置里面的开发者选项,打开Show GPU Overdraw的选项,可以观察UI上的Overdraw情况。

Android性能优化典范

蓝色,淡绿,淡红,深红代表了4种不同程度的Overdraw情况,我们的目标就是尽量减少红色Overdraw,看到更多的蓝色区域。

Overdraw有时候是因为你的UI布局存在大量重叠的部分,还有的时候是因为非必须的重叠背景。例如某个Activity有一个背景,然后里面 的Layout又有自己的背景,同时子View又分别有自己的背景。仅仅是通过移除非必须的背景图片,这就能够减少大量的红色Overdraw区域,增加 蓝色区域的占比。这一措施能够显著提升程序性能。

2)Understanding VSYNC

为了理解App是如何进行渲染的,我们必须了解手机硬件是如何工作,那么就必须理解什么是VSYNC

在讲解VSYNC之前,我们需要了解两个相关的概念:

  • Refresh Rate:代表了屏幕在一秒内刷新屏幕的次数,这取决于硬件的固定参数,例如60Hz。
  • Frame Rate:代表了GPU在一秒内绘制操作的帧数,例如30fps,60fps。

GPU会获取图形数据进行渲染,然后硬件负责把渲染后的内容呈现到屏幕上,他们两者不停的进行协作。

Android性能优化典范

不幸的是,刷新频率和帧率并不是总能够保持相同的节奏。如果发生帧率与刷新频率不一致的情况,就会容易出现Tearing的现象(画面上下两部分显示内容发生断裂,来自不同的两帧数据发生重叠)。

Android性能优化典范

Android性能优化典范

理解图像渲染里面的双重与三重缓存机制,这个概念比较复杂。

通常来说,帧率超过刷新频率只是一种理想的状况,在超过60fps的情况下,GPU所产生的帧数据会因为等待VSYNC的刷新信息而被Hold住,这样能够保持每次刷新都有实际的新的数据可以显示。但是我们遇到更多的情况是帧率小于刷新频率。

Android性能优化典范

在这种情况下,某些帧显示的画面内容就会与上一帧的画面相同。糟糕的事情是,帧率从超过60fps突然掉到60fps以下,这样就会发生LAGJANKHITCHING等卡顿掉帧的不顺滑的情况。这也是用户感受不好的原因所在。

3)Tool:Profile GPU Rendering

性能问题如此的麻烦,幸好我们可以有工具来进行调试。打开手机里面的开发者选项,选择Profile GPU Rendering,选中On screen as bars的选项。

Android性能优化典范

选择了这样以后,我们可以在手机画面上看到丰富的GPU绘制图形信息,分别关于StatusBar,NavBar,激活的程序Activity区域的GPU Rending信息。

Android性能优化典范

随着界面的刷新,界面上会滚动显示垂直的柱状图来表示每帧画面所需要渲染的时间,柱状图越高表示花费的渲染时间越长。

Android性能优化典范

中间有一根绿色的横线,代表16ms,我们需要确保每一帧花费的总时间都低于这条横线,这样才能够避免出现卡顿的问题。

Android性能优化典范

每一条柱状线都包含三部分,蓝色代表测量绘制Display List的时间,红色代表OpenGL渲染Display List所需要的时间,黄色代表CPU等待GPU处理的时间。

4)Why 60fps?

我们通常都会提到60fps与16ms,可是知道为何会是以程序是否达到60fps来作为App性能的衡量标准吗?这是因为人眼与大脑之间的协作无法感知超过60fps的画面更新。

12fps大概类似手动快速翻动书籍的帧率,这明显是可以感知到不够顺滑的。24fps使得人眼感知的是连续线性的运动,这其实是归功于运动模糊的 效果。24fps是电影胶圈通常使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够*大的减少费用支出。但是低于30fps是 无法顺畅表现绚丽的画面内容的,此时就需要用到60fps来达到想要的效果,当然超过60fps是没有必要的。

开发app的性能目标就是保持60fps,这意味着每一帧你只有16ms=1000/60的时间来处理所有的任务。

5)Android, UI and the GPU

了解Android是如何利用GPU进行画面渲染有助于我们更好的理解性能问题。那么一个*实际的问题是:activity的画面是如何绘制到屏幕上的?那些复杂的XML布局文件又是如何能够被识别并绘制出来的?

Android性能优化典范

Resterization栅格化是绘制那些Button,Shape,Path,String,Bitmap等组件*基础的操作。它把那些组件拆分到不同的像素上进行显示。这是一个很费时的操作,GPU的引入就是为了加快栅格化的操作。

CPU负责把UI组件计算成Polygons,Texture纹理,然后交给GPU进行栅格化渲染。

Android性能优化典范

然而每次从CPU转移到GPU是一件很麻烦的事情,所幸的是OpenGL ES可以把那些需要渲染的纹理Hold在GPU Memory里面,在下次需要渲染的时候直接进行操作。所以如果你更新了GPU所hold住的纹理内容,那么之前保存的状态就丢失了。

在Android里面那些由主题所提供的资源,例如Bitmaps,Drawables都是一起打包到统一的Texture纹理当中,然后再传递到 GPU里面,这意味着每次你需要使用这些资源的时候,都是直接从纹理里面进行获取渲染的。当然随着UI组件的越来越丰富,有了更多演变的形态。例如显示图 片的时候,需要先经过CPU的计算加载到内存中,然后传递给GPU进行渲染。文字的显示更加复杂,需要先经过CPU换算成纹理,然后再交给GPU进行渲 染,回到CPU绘制单个字符的时候,再重新引用经过GPU渲染的内容。动画则是一个更加复杂的操作流程。

为了能够使得App流畅,我们需要在每一帧16ms以内处理完所有的CPU与GPU计算,绘制,渲染等等操作。

6)Invalidations, Layouts, and Performance

顺滑精妙的动画是app设计里面*重要的元素之一,这些动画能够显著提升用户体验。下面会讲解Android系统是如何处理UI组件的更新操作的。

通常来说,Android需要把XML布局文件转换成GPU能够识别并绘制的对象。这个操作是在DisplayList的帮助下完成的。DisplayList持有所有将要交给GPU绘制到屏幕上的数据信息。

在某个View*次需要被渲染时,DisplayList会因此而被创建,当这个View要显示到屏幕上时,我们会执行GPU的绘制指令来进行渲 染。如果你在后续有执行类似移动这个View的位置等操作而需要再次渲染这个View时,我们就仅仅需要额外操作一次渲染指令就够了。然而如果你修改了 View中的某些可见组件,那么之前的DisplayList就无法继续使用了,我们需要回头重新创建一个DisplayList并且重新执行渲染指令并 更新到屏幕上。

需要注意的是:任何时候View中的绘制内容发生变化时,都会重新执行创建DisplayList,渲染DisplayList,更新到屏幕上等一 系列操作。这个流程的表现性能取决于你的View的复杂程度,View的状态变化以及渲染管道的执行性能。举个例子,假设某个Button的大小需要增大 到目前的两倍,在增大Button大小之前,需要通过父View重新计算并摆放其他子View的位置。修改View的大小会触发整个 HierarcyView的重新计算大小的操作。如果是修改View的位置则会触发HierarchView重新计算其他View的位置。如果布局很复 杂,这就会很容易导致严重的性能问题。我们需要尽量减少Overdraw。

Android性能优化典范

我们可以通过前面介绍的Monitor GPU Rendering来查看渲染的表现性能如何,另外也可以通过开发者选项里面的Show GPU view updates来查看视图更新的操作,*后我们还可以通过HierarchyViewer这个工具来查看布局,使得布局尽量扁平化,移除非必需的UI组 件,这些操作能够减少Measure,Layout的计算时间。

7)Overdraw, Cliprect, QuickReject

引起性能问题的一个很重要的方面是因为过多复杂的绘制操作。我们可以通过工具来检测并修复标准UI组件的Overdraw问题,但是针对高度自定义的UI组件则显得有些力不从心。

有一个窍门是我们可以通过执行几个APIs方法来显著提升绘制操作的性能。前面有提到过,非可见的UI组件进行绘制更新会导致Overdraw。例 如Nav Drawer从前置可见的Activity滑出之后,如果还继续绘制那些在Nav Drawer里面不可见的UI组件,这就导致了Overdraw。为了解决这个问题,Android系统会通过避免绘制那些完全不可见的组件来尽量减少 Overdraw。那些Nav Drawer里面不可见的View就不会被执行浪费资源。

Android性能优化典范

但是不幸的是,对于那些过于复杂的自定义的View(重写了onDraw方法),Android系统无法检测具体在onDraw里面会执行什么操作,系统无法监控并自动优化,也就无法避免Overdraw了。但是我们可以通过canvas.clipRect()来 帮助系统识别那些可见的区域。这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视。这个API可以很好的帮助那些有多组重叠 组件的自定义View来控制显示的区域。同时clipRect方法还可以帮助节约CPU与GPU资源,在clipRect区域之外的绘制指令都不会被执 行,那些部分内容在矩形区域内的组件,仍然会得到绘制。

Android性能优化典范

除了clipRect方法之外,我们还可以使用canvas.quickreject()来判断是否没和某个矩形相交,从而跳过那些非矩形区域内的绘制操作。做了那些优化之后,我们可以通过上面介绍的Show GPU Overdraw来查看效果。

8)Memory Churn and performance

虽然Android有自动管理内存的机制,但是对内存的不恰当使用仍然容易引起严重的性能问题。在同一帧里面创建过多的对象是件需要特别引起注意的事情。

Android系统里面有一个Generational Heap Memory的模型,系统会根据内存中不同 的内存数据类型分别执行不同的GC操作。例如,*近刚分配的对象会放在Young Generation区域,这个区域的对象通常都是会快速被创建并且很快被销毁回收的,同时这个区域的GC操作速度也是比Old Generation区域的GC操作速度更快的。

Android性能优化典范

除了速度差异之外,执行GC操作的时候,任何线程的任何操作都会需要暂停,等待GC操作完成之后,其他操作才能够继续运行。

Android性能优化典范

通常来说,单个的GC并不会占用太多时间,但是大量不停的GC操作则会显著占用帧间隔时间(16ms)。如果在帧间隔时间里面做了过多的GC操作,那么自然其他类似计算,渲染等操作的可用时间就变得少了。

导致GC频繁执行有两个原因:

  • Memory Churn内存抖动,内存抖动是因为大量的对象被创建又在短时间内马上被释放。
  • 瞬间产生大量的对象会严重占用Young Generation的内存区域,当达到阀值,剩余空间不够的时候,也会触发GC。即使每次分配的对象占用了很少的内存,但是他们叠加在一起会增加 Heap的压力,从而触发更多其他类型的GC。这个操作有可能会影响到帧率,并使得用户感知到性能问题。

Android性能优化典范

解决上面的问题有简洁直观方法,如果你在Memory Monitor里面查看到短时间发生了多次内存的涨跌,这意味着很有可能发生了内存抖动。

Android性能优化典范

同时我们还可以通过Allocation Tracker来查看在短时间内,同一个栈中不断进出的相同对象。这是内存抖动的典型信号之一。

当你大致定位问题之后,接下去的问题修复也就显得相对直接简单了。例如,你需要避免在for循环里面分配对象占用内存,需要尝试把对象的创建移到循 环体之外,自定义View中的onDraw方法也需要引起注意,每次屏幕发生绘制以及动画执行过程中,onDraw方法都会被调用到,避免在onDraw 方法里面执行复杂的操作,避免创建对象。对于那些无法避免需要创建对象的情况,我们可以考虑对象池模型,通过对象池来解决频繁创建与销毁的问题,但是这里 需要注意结束使用之后,需要手动释放对象池中的对象。

9)Garbage Collection in Android

JVM的回收机制给开发人员带来很大的好处,不用时刻处理对象的分配与回收,可以更加专注于更加高级的代码实现。相比起Java,C与C++等语言 具备更高的执行效率,他们需要开发人员自己关注对象的分配与回收,但是在一个庞大的系统当中,还是免不了经常发生部分对象忘记回收的情况,这就是内存泄 漏。

原始JVM中的GC机制在Android中得到了很大程度上的优化。Android里面是一个三级Generation的内存模型,*近分配的对象 会存放在Young Generation区域,当这个对象在这个区域停留的时间达到一定程度,它会被移动到Old Generation,*后到Permanent Generation区域。

Android性能优化典范

每一个级别的内存区域都有固定的大小,此后不断有新的对象被分配到此区域,当这些对象总的大小快达到这一级别内存区域的阀值时,会触发GC的操作,以便腾出空间来存放其他新的对象。

Android性能优化典范

前面提到过每次GC发生的时候,所有的线程都是暂停状态的。GC所占用的时间和它是哪一个Generation也有关系,Young Generation的每次GC操作时间是*短的,Old Generation其次,Permanent Generation*长。执行时间的长短也和当前Generation中的对象数量有关,遍历查找20000个对象比起遍历50个对象自然是要慢很多 的。

虽然Google的工程师在尽量缩短每次GC所花费的时间,但是特别注意GC引起的性能问题还是很有必要。如果不小心在*小的for循环单元里面执 行了创建对象的操作,这将很容易引起GC并导致性能问题。通过Memory Monitor我们可以查看到内存的占用情况,每一次瞬间的内存降低都是因为此时发生了GC操作,如果在短时间内发生大量的内存上涨与降低的事件,这说明 很有可能这里有性能问题。我们还可以通过Heap and Allocation Tracker工具来查看此时内存中分配的到底有哪些对象。

10)Performance Cost of Memory Leaks

虽然Java有自动回收的机制,可是这不意味着Java中不存在内存泄漏的问题,而内存泄漏会很容易导致严重的性能问题。

内存泄漏指的是那些程序不再使用的对象无法被GC识别,这样就导致这个对象一直留在内存当中,占用了宝贵的内存空间。显然,这还使得每级Generation的内存区域可用空间变小,GC就会更容易被触发,从而引起性能问题。

寻找内存泄漏并修复这个漏洞是件很棘手的事情,你需要对执行的代码很熟悉,清楚的知道在特定环境下是如何运行的,然后仔细排查。例如,你想知道程序 中的某个activity退出的时候,它之前所占用的内存是否有完整的释放干净了?首先你需要在activity处于前台的时候使用Heap Tool获取一份当前状态的内存快照,然后你需要创建一个几乎不这么占用内存的空白activity用来给前一个Activity进行跳转,其次在跳转到 这个空白的activity的时候主动调用System.gc()方法来确保触发一个GC操作。*后,如果前面这个activity的内存都有全部正确释 放,那么在空白activity被启动之后的内存快照中应该不会有前面那个activity中的任何对象了。

Android性能优化典范

如果你发现在空白activity的内存快照中有一些可疑的没有被释放的对象存在,那么接下去就应该使用Alocation Track Tool来仔细查找具体的可疑对象。我们可以从空白activity开始监听,启动到观察activity,然后再回到空白activity结束监听。这样操作以后,我们可以仔细观察那些对象,找出内存泄漏的真凶。

Android性能优化典范

11)Memory Performance

通常来说,Android对GC做了大量的优化操作,虽然执行GC操作的时候会暂停其他任务,可是大多数情况下,GC操作还是相对很安静并且高效的。但是如果我们对内存的使用不恰当,导致GC频繁执行,这样就会引起不小的性能问题。

为了寻找内存的性能问题,Android Studio提供了工具来帮助开发者。

  • Memory Monitor:查看整个app所占用的内存,以及发生GC的时刻,短时间内发生大量的GC操作是一个危险的信号。
  • Allocation Tracker:使用此工具来追踪内存的分配,前面有提到过。
  • Heap Tool:查看当前内存快照,便于对比分析哪些对象有可能是泄漏了的,请参考前面的Case。

12)Tool – Memory Monitor

Android Studio中的Memory Monitor可以很好的帮组我们查看程序的内存使用情况。

Android性能优化典范

Android性能优化典范

Android性能优化典范

13)Battery Performance

电量其实是目前手持设备*宝贵的资源之一,大多数设备都需要不断的充电来维持继续使用。不幸的是,对于开发者来说,电量优化是他们*后才会考虑的的事情。但是可以确定的是,千万不能让你的应用成为消耗电量的大户。

Purdue University研究了*受欢迎的一些应用的电量消耗,平均只有30%左右的电量是被程序*核心的方法例如绘制图片,摆放布局等等所使用掉的,剩下的 70%左右的电量是被上报数据,检查位置信息,定时检索后台广告信息所使用掉的。如何平衡这两者的电量消耗,就显得非常重要了。

有下面一些措施能够显著减少电量的消耗:

  • 我们应该尽量减少唤醒屏幕的次数与持续的时间,使用WakeLock来处理唤醒的问题,能够正确执行唤醒操作并根据设定及时关闭操作进入睡眠状态。
  • 某些非必须马上执行的操作,例如上传歌曲,图片处理等,可以等到设备处于充电状态或者电量充足的时候才进行。
  • 触发网络请求的操作,每次都会保持无线信号持续一段时间,我们可以把零散的网络请求打包进行一次操作,避免过多的无线信号引起的电量消耗。关于网络请求引起无线信号的电量消耗。

我们可以通过手机设置选项找到对应App的电量消耗统计数据。我们还可以通过Battery Historian Tool来查看详细的电量消耗。

Android性能优化典范

如果发现我们的App有电量消耗过多的问题,我们可以使用JobScheduler API来对一些任务进行定时处理,例如我们可以把那些任务重的操作等到手机处于充电状态,或者是连接到WiFi的时候来处理。

14)Understanding Battery Drain on Android

电量消耗的计算与统计是一件麻烦而且矛盾的事情,记录电量消耗本身也是一个费电量的事情。唯一可行的方案是使用第三方监测电量的设备,这样才能够获取到真实的电量消耗。

当设备处于待机状态时消耗的电量是*少的,以N5为例,打开飞行模式,可以待机接近1个月。可是点亮屏幕,硬件各个模块就需要开始工作,这会需要消耗很多电量。

使用WakeLock或者JobScheduler唤醒设备处理定时的任务之后,一定要及时让设备回到初始状态。每次唤醒无线信号进行数据传递,都会消耗很多电量,它比WiFi等操作更加的耗电。

Android性能优化典范

修复电量的消耗是另外一个很大的课题,这里就不展开继续了。

15)Battery Drain and WakeLocks

高效的保留更多的电量与不断促使用户使用你的App来消耗电量,这是矛盾的选择题。不过我们可以使用一些更好的办法来平衡两者。

假设你的手机里面装了大量的社交类应用,即使手机处于待机状态,也会经常被这些应用唤醒用来检查同步新的数据信息。Android会不断关闭各种硬 件来延长手机的待机时间,首先屏幕会逐渐变暗直至关闭,然后CPU进入睡眠,这一切操作都是为了节约宝贵的电量资源。但是即使在这种睡眠状态下,大多数应 用还是会尝试进行工作,他们将不断的唤醒手机。一个*简单的唤醒手机的方法是使用PowerManager.WakeLock的API来保持CPU工作并 防止屏幕变暗关闭。这使得手机可以被唤醒,执行工作,然后回到睡眠状态。知道如何获取WakeLock是简单的,可是及时释放WakeLock也是非常重 要的,不恰当的使用WakeLock会导致严重错误。例如网络请求的数据返回时间不确定,导致本来只需要10s的事情一直等待了1个小时,这样会使得电量 白白浪费了。这也是为何使用带超时参数的wakelock.acquice()方法是很关键的。但是仅仅设置超时并不足够解决问题,例如设置多长的超时比 较合适?什么时候进行重试等等?

解决上面的问题,正确的方式可能是使用非精准定时器。通常情况下,我们会设定一个时间进行某个操作,但是动态修改这个时间也许会更好。例如,如果有 另外一个程序需要比你设定的时间晚5分钟唤醒,*好能够等到那个时候,两个任务捆绑一起同时进行,这就是非精确定时器的核心工作原理。我们可以定制计划的 任务,可是系统如果检测到一个更好的时间,它可以推迟你的任务,以节省电量消耗。

Android性能优化典范

这正是JobScheduler API所做的事情。它会根据当前的情况与任务,组合出理想的唤醒时间,例如等到正在充电或者连接到WiFi的时候,或者集中任务一起执行。我们可以通过这个API实现很多免费的调度算法。

从Android 5.0开始发布了Battery History Tool,它可以查看程序被唤醒的频率,又谁唤醒的,持续了多长的时间,这些信息都可以获取到。

请关注程序的电量消耗,用户可以通过手机的设置选项观察到那些耗电量大户,并可能决定卸载他们。所以尽量减少程序的电量消耗是非常有必要的。

Android UI优化—Listview 重用convertView

1.重用convertView

我们对convertView添加判断,如果存在我们就直接使用,否则初始化一个convertView的实例。(如下图)

这里写图片描述

2.使用viewHolder

使用viewHolder并且是一个静态的匿名内部类。(如下图)

这里写图片描述

3.在列表里面有图片的情况下,监听滑动不加载图片

1.可以查看一下我的这篇文章Listview

2.这个建议用一些图片请求框架,如:Android-Universal-Image-Loader,推荐个中文解析的网站http://codekk.com/

4.多个不同布局,可以创建不同的viewHolder和convertView进行重用

比如聊天:左边一个布局,右边一个布局,我们可以创建不同的viewHolder,并且对convertView进行判断每个不同的convertView只初始化一次。

Android UI优化—使用stytle

使用style替换背景,防止Activity黑色背景闪过


1.原来的布局

复制代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="@drawable/img_bg"
              android:orientation="horizontal">

    <Button
        android:layout_weight="1"
        android:layout_width="0"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/button2"/>

    <Button
        android:layout_weight="1"
        android:layout_width="0"
        android:layout_height="wrap_content"
        android:text="New Button1"
        android:id="@+id/button3"/>


</LinearLayout>
复制代码

 

这里写图片描述

这里我们用了android:background="@drawable/img_bg"来设置了背景图片,但是当我们启动activity是有时候会出现一个黑色的背景,然后才出现我们设置的背景,给用户感觉我们的程序运行的很慢

2.解决办法

复制代码
<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="android:background">@drawable/img_bg</item>
    </style>
</resources>
复制代码

我们可以给主题设置一个背景,这样就不会给用户感觉我们的应用卡住了

3.知其然知其所以然

1.因为程序的主题是在程序启动的时候加载
2.Layout中设置的背景实在Activity启动之后才加载
所以会让用户看到一个黑色背景闪过的过程。

Android UI优化—使用ViewStub延迟加载

使用ViewStub延迟加载


1.ViewStub延迟加载

ViewStub是一个不可见的,大小为0的View,*佳用途就是实现View的延迟加载,在需要的时候再加载View,可Java中常见的性能优化方法延迟加载一样。
当调用ViewStub的setVisibility函数设置为可见或则调用inflate初始化该View的时候,ViewStub引用的资源开始初始 化,然后引用的资源替代ViewStub自己的位置填充在ViewStub的位置。因此在没有调用setVisibility(int)或则 inflate()函数之前ViewStub一种存在组件树层级结构中,但是由于ViewStub非常轻量级,这对性能影响非常小。 可以通过ViewStub的inflatedId属性来重新定义引用的layout id。 例如:

  • xml
<ViewStub
        android:id="@+id/stub"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:inflatedId="@+id/subTree"
        android:layout="@layout/activity_viewstub_item"/>
  • java
复制代码
//获取到viewstub
final ViewStub stub = (ViewStub) findViewById(R.id.stub);
//测试用inflate()填充布局
Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        View view = stub.inflate();
    }
};
handler.sendEmptyMessageDelayed(1, 7000);
复制代码
 

我这里间隔了一段时间去调用了stub.inflate();方法,加载布局,我们这里就不用再去findViewById去加载view了

  • 效果

这里写图片描述

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速