本文目录一览:
- 1、elasticsearch java 怎么设置 ignore
- 2、JDK中如何配置process-wide过滤器
- 3、为什么在我的eclipse里提示没有File.getFreeSpace()、File.getUsableSpace()、File.getTotalSpace()的定义
- 4、如何在服务器上配置Tomcat和JDK
elasticsearch java 怎么设置 ignore
今天,事情终于发生了。Java6(Mustang),是2006年早些时候出来的,至今仍然应用在众多生产环境中,现在终于走到了尽头。已经没有什么理由阻止迁移到Java7(Dolphin)上了。
这也促使我想写一篇关于在ElasticSearch上配置Java6和7的细微差异的博文。
Elasticsearch对Java虚拟机进行了预先的配置。通常情况下,因为这些配置的选择还是很谨慎的,所以你不需要太关心,并且你能立刻使用ElasticSearch。
但是,当你监视ElasticSearch节点内存时,你可能尝试修改一些配置。这些修改是否会改善你的处境?
这篇博文尝试揭开Elasticsearch配置的神秘面纱,并且讨论最常见的调整。最终,会给出一些推荐的配置调整。
Elasticsearch JVM 配置概览:
这些是Elasticsearch 0.19.11版本的默认配置。
JVM参数 Elasticsearch默认值 Environment变量
-Xms 256m ES_MIN_MEM
-Xmx 1g ES_MAX_MEM
-Xms and -Xmx ES_HEAP_SIZE
-Xmn ES_HEAP_NEWSIZE
-XX:MaxDirectMemorySize ES_DIRECT_SIZE
-Xss 256k
-XX:UseParNewGC +
-XX:UseConcMarkSweepGC +
-XX:CMSInitiatingOccupancyFraction 75
-XX:UseCMSInitiatingOccupancyOnly +
-XX:UseCondCardMark (commented out)
首先你注意到的是,Elasticsearch预留了256M到1GB的堆内存。
这个设置适用于开发和演示环境。开发人员只需要简单的解压发行包,再执行./bin/elasticsearch -f就完成了Elasticsearch的安装。当然这点对于开发来说非常棒,并且在很多场景下都能工作,但是当你需要更多内存来降低Elasticsearch负载的时候就不行了,你需要比2GB RAM更多的可用内存。
ES_MIN_MEM/ES_MAX_MEM是控制堆大小的配置。新的ES_HEAP_SIZE变量是一个更为便利的选择,因为将堆的初始大小和最大值设为相同。也推荐在分配堆内存时尽可能不要用内存的碎片。内存碎片对于性能优化来说非常不利。
ES_HEAP_NEWSIZE是可选参数,它控制堆的子集大小,也就是新生代的大小。
ES_DIRECT_SIZE控制本机直接内存大小,即JVM管理NIO框架中使用的数据区域大小。本机直接内存可以被映射到虚拟地址空间上,这样在64位的机器上更高效,因为可以规避文件系统缓冲。Elasticsearch对本机直接内存没有限制(可能导致OOM)。
由于历史原因Java虚拟机有多个垃圾收集器。可以通过以下的JVM参数组合启用:
JVM parameter Garbage collector
-XX:+UseSerialGC serial collector
-XX:+UseParallelGC parallel collector
-XX:+UseParallelOldGC Parallel compacting collector
-XX:+UseConcMarkSweepGC Concurrent-Mark-Sweep (CMS) collector
-XX:+UseG1GC Garbage-First collector (G1)
UseParNewGC和UseConcMarkSweepGC组合启用垃圾收集器的并发多线程模式。UseConcMarkSweepGC自动选择UseParNewGC模式并禁用串行收集器(Serial collector)。在Java6中这是默认行为。
CMSInitiatingOccupancyFraction提炼了一种CMS(Concurrent-Mark-Sweep)垃圾收集设置;它将旧生代触发垃圾收集的阀值设为75.旧生代的大小是堆大小减去新生代大小。这告诉JVM当堆内容达到75%时启用垃圾收集。这是个估计的值,因为越小的堆可能需要越早启动GC。
UseCondCardMark将在垃圾收集器的card table使用时,在marking之前进行额外的判断,避免冗余的store操作。UseCondCardMark不影响Garbage-First收集器。强烈推荐在高并发场景下配置这个参数(规避card table marking技术在高并发场景下的降低吞吐量的负面作用)。在ElasticSearch中,这个参数是被注释掉的。
有些配置可以参考诸如Apache Cassandra项目,他们在JVM上有类似的需求。
总而言之,ElastciSearch配置上推荐:
1. 不采用自动的堆内存配置,将堆大小默认最大值设为1GB
2.调整触发垃圾收集的阀值,比如将gc设为75%堆大小的时候触发,这样不会影响性能。
3.禁用Java7默认的G1收集器,前提是你的ElasticSearch跑在Java7u4以上的版本上。
JVM进程的内存结果
JVM内存由几部分组成:
Java代码本身:包括内部代码、数据、接口,调试和监控代理或者字节码指令
非堆内存:用于加载类
栈内存:用于为每个线程存储本地变量和操作数
堆内存:用于存放对象引用和对象本身
直接缓冲区:用于缓冲I/O数据
堆内存的大小设置非常重要,因为Java的运行依赖于合理的堆大小,并且JVM需要从操作系统那获取有限的堆内存,用于支撑整个JVM生命周期。
如果堆太小,垃圾回收就会频繁发生,发生OOM的几率会很大。
如果堆太大,垃圾回收会延迟,但是一旦回收,就需要处理大量的存活堆数据。并且,操作系统的压力也会变大,因为JVM进程需要更大的堆,产生换页的可能性就会提高。
注意,使用CMS垃圾收集器,Java不会把内存还给操作系统,因此配置合理的堆初始值和最大值就非常重要。
非堆内存由Java应用自动分配。没有什么参数控制这里的大小,这是由Java应用程序代码自己决定的。
栈内存在每个线程中分配,在Elasticsearch中,每个线程大小必须由128K增加到256K,因为Java7比Java6需要更大的栈内存 ,这是由于Java7支持新的编程语言特征来利用栈空间。比如,引入了continuations模型,编程语言的一个著名概念。Continuations模型对于
协同程序、绿色线程(green thread)、纤程(fiber)非常有用 。当实现非阻塞I/O时,一个大的优势是,代码可以根据线程实际使用情况编写,但是运行时仍然在后台采用非阻塞I/O。Elasticsearch使用了多个线程池,因为Netty I/O框架和Guava是Elasticsearch的基础组件,因此在用Java7时,可以考虑进一步挖掘优化线程的特性。
发挥增加栈空间大小的优势还是有挑战的,因为不同的操作系统、不同的CPU架构,甚至在不同的JVM版本之间,栈空间的消耗不是容易比较的。取决于CPU架构和操作系统,JVM的栈空间大小是内建的。他们是否在所有场景下都适合?例如Sloaris Sparc 64位的JVM Xss默认为512K,因为有更大地址指针,Sloaris X86为320K。Linux降为256K。Windows 32位Java6默认320K,Windows 64位则为1024K。
大堆的挑战
今天,几GB的内存是很常见的。但是在不久以前,系统管理员还在为多几G的内存需求泪流满面。
Java垃圾收集器是随着2006年的Java6的出现而显著改进的。从那以后,可以并发执行多任务,并且减少了GC停顿几率: stop - the - world阶段。CMS算法是革命性的,多任务,并发, 不需要移动的GC。但是不幸的是,对于堆的存活数据量来说,它是不可扩展的。Prateek Khanna 和 Aaron Morton给出了CMS垃圾收集器能够处理的堆规模的数字。
避免Stop-the-world阶段
我们已经学习了Elasticsearch如何配置CMS垃圾收集器。但这并不能组织长时间的GC停顿,它只是降低了发生的几率。CMS是一个低停顿几率的收集器,但是仍然有一些边界情况。当堆上有MB级别的大数组,或者其他一些特殊的场景,CMS可能比预期要花费更多的时间。
MB级别数组的创建在Lucene segment-based索引合并时是很常见的。如果你希望降低CMS的额外负载,就需要调整Lucene合并阶段的段数量,使用参数index.merge.policy.segments_per_tier
减少换页
大堆的风险在于内存压力上。注意,如果Java JVM在处理大堆时,这部分内存对于系统其它部分来说是不可用的。如果内存吃紧,操作系统会进行换页,并且,在紧急情况下,当所有其他方式回收内存都失败时,会强制杀掉进程。如果换页发生,整个系统的性能会下降,自然GC的性能也跟着下降。所以,不要给堆分配太多的内存。
垃圾收集器的选择
从Java JDK 7u4开始,Garbage-First(G1)收集器是Java7默认的垃圾收集器。它适用于多核的机器以及大内存。它一方面降低了停顿时间,另一方面增加了停顿的次数。整个堆的操作,例如全局标记,是在应用线程中并发执行的。这会防止随着堆或存活数据大小的变化,中断时间也成比例的变化。
G1收集器目标是获取更高的吞吐量,而不是速度。在以下情况下,它能运行的很好:
1. 存活数据占用了超过50%的Java堆
2. 对象分配比例或者promotion会有明显的变化
3. 不希望gc或者compaction停顿时间长(超过0.5至1s)
注意,如果使用G1垃圾收集器,堆不再使用的内存可能会被归还给操作系统
G1垃圾收集器的不足是CPU使用率越高,应用性能越差。因此,如果在内存足够和CPU能力一般的情况下,CMS可能更胜一筹。
对于Elasticsearch来说,G1意味着没有长时间的stop-the-world阶段,以及更灵活的内存管理,因为buffer memory和系统I/O缓存能更充分的利用机器内存资源。代价就是小成本的最大化性能,因为G1利用了更多CPU资源。
性能调优策略
你读这篇博文因为你希望在性能调优上得到一些启示:
1. 清楚了解你的性能目标。你希望最大化速度,还是最大化吞吐量?
2. 记录任何事情(log everything),收集统计数据,阅读日志、分析事件来诊断配置
3. 选择你调整的目标(最大化性能还是最大化吞吐量)
4. 计划你的调整
5. 应用你的新配置
6. 监控新配置后的系统
7. 如果新配置没有改善你的处境,重复上面的一系列动作,反复尝试
Elasticsearch垃圾收集日志格式
Elasticsearch长时间GC下warns级别的日志如下所示:
[2012-11-26 18:13:53,166][WARN ][monitor.jvm ] [Ectokid] [gc][ParNew][1135087][11248] duration [2.6m], collections [1]/[2.7m], total [2.6m]/[6.8m], memory [2.4gb]-[2.3gb]/[3.8gb], all_pools {[Code Cache] [13.7mb]-[13.7mb]/[48mb]}{[Par Eden Space] [109.6mb]-[15.4mb]/[1gb]}{[Par Survivor Space] [136.5mb]-[0b]/[136.5mb]}{[CMS Old Gen] [2.1gb]-[2.3gb]/[2.6gb]}{[CMS Perm Gen] [35.1mb]-[34.9mb]/[82mb]}
JvmMonitorService类中有相关的使用方式:
Logfile Explanation
gc 运行中的gc
ParNew new parallel garbage collector
duration 2.6m gc时间为2.6分钟
collections [1]/[2.7m] 在跑一个收集,共花2.7分钟
memory [2.4gb]-[2.3gb]/[3.8gb] 内存消耗, 开始是2.4gb, 现在是2.3gb, 共有3.8gb内存
Code Cache [13.7mb]-[13.7mb]/[48mb] code cache占用内存
Par Eden Space [109.6mb]-[15.4mb]/[1gb] Par Eden Space占用内存
Par Survivor Space [136.5mb]-[0b]/[136.5mb] Par Survivor Space占用内存
CMS Old Gen [2.1gb]-[2.3gb]/[2.6gb] CMS Old Gen占用内存
CMS Perm Gen [35.1mb]-[34.9mb]/[82mb] CMS Perm Gen占用内存
JvmMonitorSer
一些建议
1. 不要在Java 6u22之前的发布版本中跑Elasticsearch。有内存方面的bug。那些超过两三年的bug和缺陷会妨碍Elasticsearch的正常运行。与旧的OpenJDK 6相比,更推荐Sun/Oracle的版本,因为后者修复了很多bug。
2. 放弃Java6,转到Java7。Oracle宣称Java6更新到2013年2月结束。考虑到Elasticsearch还是一个相对新的软件,应该使用更新的技术来提升性能。尽量从JVM中挤压性能。检查操作系统的版本。在最新版本的操作系统中运行,有助于你的Java运行环境达到最佳性能。
3. 定期更新Java运行环境。平均一个季度一次。告诉sa你需要及时更新Java版本,以获取Java性能的提升。
4. 从小到大。先在Elasticsearch单节点上进行开发。但是不要忘了Elasticsearch分布式的强大功能。单节点不能模拟生产环境的特征,至少需要3个节点进行开发测试。
5. 在调整JVM之前先做一下性能测试。对你的系统建立性能基线。调整测试时候的节点数量。如果索引时候负载很高,你可能需要降低Elasticsearch索引时候占用的堆大小,通过index.merge.policy.segments_per_tierparameter参数调整段的合并。
6. 调整前清楚你的性能目标,然后决定是调整速度还是吞吐量。
7. 启用日志以便更好的进行诊断。在优化系统前进行小心的评估。
8. 如果使用CMS垃圾收集器,你可能需要加上合理的 -XX:CMSWaitDuration 参数。
9. 如果你的堆超过6-8GB,超过了CMS垃圾收集器设计容量,你会遇到长时间的stop-the-world阶段,你有几个方案:调整CMSInitiatingOccupancyFraction参数降低长时间GC的几率减少最大堆的大小;启用G1垃圾收集器。
10. 学习垃圾收集调优艺术。如果你想精通的话,列出可用的JVM选项,在java命令中加入java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version,然后调优。
JDK中如何配置process-wide过滤器
首先下载JDK保存到电脑硬盘
如何配置JDK环境变量
双击进行安装,选择安装路径,作者选择安装到C:\Program Files\Java
如何配置JDK环境变量
打开我的电脑—属性
如何配置JDK环境变量
点击高级菜单
如何配置JDK环境变量
选中环境变量
如何配置JDK环境变量
新建环境变量“Java_Home”值:JDK所在的绝对路径C:\ProgramFiles\Java\jdk1.6.0_41
如何配置JDK环境变量
新建“Classpath”(如果已有,则直接编辑),值: .;%Java_Home%\lib (若值中原来有内容,用分号与之隔开)。
如何配置JDK环境变量
新建“Path”(如果已有,则直接编辑),值: %Java_Home%\bin; (若值中原来有内容,用分号与之隔开)。
如何配置JDK环境变量
ok,进行完以上动作,配置就算完成,关闭环境变量配置窗口,按windows+r键,输入cmd进入命令提示
如何配置JDK环境变量
在命令提示窗口输入“javac”,如果出现一系列命令代码,则证明配置JDK成功
如何配置JDK环境变量
为什么在我的eclipse里提示没有File.getFreeSpace()、File.getUsableSpace()、File.getTotalSpace()的定义
你确定你按装的是JDK6吗?
这些方法是JDK6里的
JDK 6
JDK5 的API
方法摘要
boolean canRead()
测试应用程序是否可以读取此抽象路径名表示的文件。
boolean canWrite()
测试应用程序是否可以修改此抽象路径名表示的文件。
int compareTo(File pathname)
按字母顺序比较两个抽象路径名。
boolean createNewFile()
当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件。
static File createTempFile(String prefix, String suffix)
在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。
static File createTempFile(String prefix, String suffix, File directory)
在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。
boolean delete()
删除此抽象路径名表示的文件或目录。
void deleteOnExit()
在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。
boolean equals(Object obj)
测试此抽象路径名与给定对象是否相等。
boolean exists()
测试此抽象路径名表示的文件或目录是否存在。
File getAbsoluteFile()
返回抽象路径名的绝对路径名形式。
String getAbsolutePath()
返回抽象路径名的绝对路径名字符串。
File getCanonicalFile()
返回此抽象路径名的规范形式。
String getCanonicalPath()
返回抽象路径名的规范路径名字符串。
String getName()
返回由此抽象路径名表示的文件或目录的名称。
String getParent()
返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null。
File getParentFile()
返回此抽象路径名的父路径名的抽象路径名,如果此路径名没有指定父目录,则返回 null。
String getPath()
将此抽象路径名转换为一个路径名字符串。
int hashCode()
计算此抽象路径名的哈希码。
boolean isAbsolute()
测试此抽象路径名是否为绝对路径名。
boolean isDirectory()
测试此抽象路径名表示的文件是否是一个目录。
boolean isFile()
测试此抽象路径名表示的文件是否是一个标准文件。
boolean isHidden()
测试此抽象路径名指定的文件是否是一个隐藏文件。
long lastModified()
返回此抽象路径名表示的文件最后一次被修改的时间。
long length()
返回由此抽象路径名表示的文件的长度。
String[] list()
返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。
String[] list(FilenameFilter filter)
返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的。
File[] listFiles()
返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。
File[] listFiles(FileFilter filter)
返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。
File[] listFiles(FilenameFilter filter)
返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。
static File[] listRoots()
列出可用的文件系统根目录。
boolean mkdir()
创建此抽象路径名指定的目录。
boolean mkdirs()
创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。
boolean renameTo(File dest)
重新命名此抽象路径名表示的文件。
boolean setLastModified(long time)
设置由此抽象路径名所指定的文件或目录的最后一次修改时间。
boolean setReadOnly()
标记此抽象路径名指定的文件或目录,以便只可对其进行读操作。
String toString()
返回此抽象路径名的路径名字符串。
URI toURI()
构造一个表示此抽象路径名的 file: URI。
URL toURL()
将此抽象路径名转换成一个 file: URL。
如何在服务器上配置Tomcat和JDK
以下文章内容及软件下载均有郑州景安计算机网络技术有限公司/郑州景安互联网数据中心制作、提供
制作环境:
Windows 2003 + IIS6、jre1.5.0_06、apache-tomcat-5.5.17
首先需要做以下准备工作
1、安装好 Tomcat 和 IIS6,并且都能正常运行
2、Tomcat的端口没做任何修改
3、下载集成需要的文件
-apache-tomcat-5.5.25.exe
-jdk-1_5_0_13-windows-i586-p.exe
-isapi_redirector2.rar
集成步骤
1、配置环境变量 JAVA_HOME 和 TOMCAT_HOME
2、将 isapi_redirector2.dll 文件拷贝到 TOMCAT_HOME 中的任意一个目录中,如:TOMCAT_HOME/iis 此目录需要新建
3、新建一个目录存放站点,如:d:\web 并在其中新建一个 ROOT 目录,此目录作为站点的默认起始目录
4、打开 IIS 控制台,新建一个站点,如果自己有域名的话可以在主机头中输入自己的域名,
如: 这样就不会和原来的默认网站冲突了,现在需要将默认网关停止后再新建
5、新建一个虚拟目录,名称为:jakarta 这个名称不能改变,路径为 TOMCAT_HOME/iis ,也就是放 dll 文件的 目录
打开站点属性窗口,进入 ISAPI 筛选器,点击添加铵钮,在筛选器名称中输入 jakarta ,这个名字也不能修改,所以要注意是否正确,
在可执行文件中选择 TOMCAT_HOME/iis/isapi_redirector2.dll 文件
进入主目录选项卡,在弹出窗口中选择添加,这里对 jsp 文件和 struts 的 do 访问方式进行映射配置,点击添加铵钮,
可执行文件选择 TOMCAT_HOME/iis/isapi_redirector2.dll ,扩展名为 jsp ,同样对 do 也进行配置
6、新增一个 Web 服务扩展,扩展名随意填,如: Tomcat ,要求的文件选择 TOMCAT_HOME/iis/isapi_redirector2.dll ,
选中设置扩展状态为充许项,然后确定
7、拷贝 jk2.properties 、 workers2.properties 两个文件到 TOMCAT_HOME/conf 目录中
jk2.properties 文件内容如下:
request.tomcatAuthentication=false
workers2.properties 文件内容如下:( 以下第二行的文件路径需要根据自己的配置进行修改 )
[shm]
file= d:/Tomcat/logs/jk2.log
size=1048576
# Example socket channel, override port and host.
[channel.socket:localhost:8009]
port=8009
host=127.0.0.1
# define the worker
[ajp13:localhost:8009]
channel=channel.socket:localhost:8009
# Uri mapping
[uri:/*.jsp]
[uri:/*.do]
[uri:/do/*]
worker=ajp13:localhost:8009
# define the worker
[status:status]
# Uri mapping
[uri:/jkstatus/*]
worker=status:status
注意 # Uri mapping 部份,现在已经开通了对jsp文件和struts的两种访问方式,如果还有其它的文件访问需要转到Tomcat来处理的话都在此进行配置
8、现打开注册表文件, 修改绿色字体部份,注意路径表示符
文件内容如下:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\2.0]
"serverRoot"=" D:\\Tomcat "
"extensionUri"="/jakarta/isapi_redirector2.dll"
"workersFile"=" D:\\Tomcat\\conf\\workers2.properties "
"logLevel"="DEBUG"
修改完成后将导入注册表(双击此文件)
9、修改 tomcat 的配置文件 server.xml
使用以下内容替换原来的 host.../host 内容, 绿色字体为需要修改的内容
Host name=" localhost " debug="0" appBase=" d:\web " unpackWARs="true" autoDeploy="true"
Logger className="org.apache.catalina.logger.FileLogger" directory="logs" prefix=" oksonic_log. " suffix=".txt" timestamp="true"/
Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix=" oksonic_access_log. " suffix=".txt" pattern="common" resolveHosts="false"/
/Host
拷贝 Tomcat_Home/webapps/ROOT 下的文件到 web/ROOT 中
重启IIS和Tomcat服务
打开浏览器输入 进行测试,正常的话可以显示 Tomcat 默认的首页
这时再进入到 IIS 的管理工具中查看ISAPI筛选器,这时应该显示一个绿色向上的箭头,如果没有绿色箭头的话应该是有一个红色的向下的箭头,这表明是配置有问题,请检查,如果一个箭头也没有的话应该是没有使用浏览进行测试,只要有一遍测试的话就应该有箭头了
这里配置完成后有一个问题,就是无法使用 直接打开 index.jsp ,
即使是配置了IIS6的默认首页也不行,我采用的方法是使用一个 index.htm 文件来进行跳转,文件内容如下:
!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"";
html
head
meta http-equiv="refresh" content="0; url=/index.jsp"
/head
body
/body
/html
整个配置基本完成,现在需要解决乱码的问题,如果有遇到乱码问题的话
这里使用的全是 UTF-8
在项目中要使用 UTF-8 的编码,并配置了过滤器,过滤编码也是 UTF-8
修改 Tomcat 的配置文件 server.xml ,在端器配置的地方加入 URIEncoding="UTF-8"
如:
Connector URIEncoding="UTF-8"
port="8080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" /
这里是Tomcat使用的编码,还要配置集成时使用的编码,因为集成时使用的端口为 8009 所以在配置8009端口的地方也要加入 URIEncoding="UTF-8"
如:
Connector URIEncoding="UTF-8"
port="8009"
enableLookups="false" redirectPort="8443" protocol="AJP/1.3" /
好了,重启 IIS 服务和 Tomcat 服务,整个集成工作就完成了
在这里我无法对乱码问题进行测试,这是我在开发时所发现并已经解决的方法,希望对大家有用。