11 个简单的 Java 性能调优技巧 大多数开发人员天经地义地以为功用优化很杂乱,需求许多的经历和常识。好吧,不能说这是彻底过错的。优化运用程序以取得最佳功用不是一件简略的作业。可是,这并不意味着如果你不具备这些常识,就不能做任何作业。这里有11个易于遵从的主张和最佳实践能够协助你创立一个功用杰出的运用程序。java-logo-6大部分主张是针对Java的。但也有若干主张是与言语无关的,能够运用于一切运用程序和编程言语。在评论专门针对Java的功用调优技巧之前,让我们先来看看通用技巧。1.在你知道必要之前不要优化这可能是最重要的功用调整技巧之一。你应该遵从常见的最佳实践做法并测验高效地完成用例。可是,这并不意味着在你证明必要之前,你应该替换任何规范库或构建杂乱的优化。在大多数状况下,过早优化不光会占用许多时刻,并且会使代码变得难以阅览和保护。更糟糕的是,这些优化一般不会带来任何优点,因为你花费许多时刻来优化的是运用程序的非要害部分。那么,你怎么证明你需求优化一些东西呢?首要,你需求界说运用程序代码的速度得多快,例如,为一切API调用指定最大呼应时刻,或许指定在特定时刻规模内要导入的记载数量。在完结这些之后,你就能够丈量运用程序的哪些部分太慢需求改进。然后,接着看第二个技巧。2.运用剖析器查找真实的瓶颈在你遵从第一个主张并断定了运用程序的某些部分需求改进后,那么从哪里开端呢?你能够用两种办法来处理问题:查看你的代码,并从看起来可疑或许你觉得可能会发作问题的部分开端。或许运用剖析器并获取有关代码每个部分的行为和功用的详细信息。期望不需求我解说为什么应该一直遵从第二种办法的原因。很明显,根据剖析器的办法能够让你更好地了解代码的功用影响,并使你能够专心于最要害的部分。如果你曾运用过剖析器,那么你必定记住从前你是多么惊奇于一下就找到了代码的哪些部分发作了功用问题。老实说,我第一次的猜想不止一次地导致我走错了方向。3.为整个运用程序创立功用测验套件这是另一个通用技巧,能够协助你防止在将功用改进布置到生产后常常会发作的许多意外问题。你应该总是界说一个测验整个运用程序的功用测验套件,并在功用改进之前和之后运转它。这些额定的测验运转将协助你辨认更改的功用和功用副作用,并保证不会导致弊大于利的更新。如果你作业于被运用程序若干不同部分运用的组件,如数据库或缓存,那么这一点就特别重要。4.首要处理最大的瓶颈在创立测验套件并运用剖析器剖析运用程序之后,你能够列出一系列需求处理以进步功用的问题。这很好,但它仍然不能答复你应该从哪里开端的问题。你能够专心于速效计划,或从最重要的问题开端。速效计划一开端可能会很有吸引力,因为你能够很快显现第一个作用。但有时,可能需求你压服其他团队成员或办理层以为功用剖析是值得的——因为暂时看不到作用。但总的来说,我主张首要处理最重要的功用问题。这将为你供给最大的功用改进,并且可能再也不需求去处理其间一些为了满意功用需求的问题。常见的功用调整技巧到此结束。下面让我们细心看看一些特定于Java的技巧。5.运用StringBuilder以编程办法衔接String有许多不同的选项来衔接Java中的String。例如,你能够运用简略的+或+ =,以及StringBuffer或StringBuilder。那么,你应该挑选哪种办法?答案取决于衔接String的代码。如果你是以编程办法增加新内容到String中,例如在for循环中,那么你应该运用StringBuilder。它很简略运用,并供给比StringBuffer更好的功用。但请记住,与StringBuffer比较,StringBuilder不是线程安全的,可能不适合一切用例。你只需求实例化一个新的StringBuilder并调用append办法来向String中增加一个新的部分。在你增加了一切的部分之后,你就能够调用toString()办法来检索衔接的String。下面的代码片段显现了一个简略的比如。在每次迭代期间,这个循环将i转换为一个String,并将它与一个空格一同增加到StringBuilder sb中。所以,最终,这段代码将在日志文件中写入“This is a test0 1 2 3 4 5 6 7 8 9”。StringBuilder sb = newStringBuilder(“This is a test”);for (int i=0; i<10; i++) { sb.append(i); sb.append(”“);}log.info(sb.toString());正如在代码片段中看到的那样,你能够将String的第一个元素供给给结构办法。这将创立一个新的StringBuilder,新的StringBuilder包括供给的String和16个额定字符的容量。当你向StringBuilder增加更多字符时,JVM将动态增加StringBuilder的巨细。如果你现已知道你的String将包括多少个字符,则能够将该数字供给给不同的结构办法以实例化具有界说容量的StringBuilder。这进一步进步了功率,因为它不需求动态扩展其容量。6.运用+衔接一个语句中的String当你用Java完成你的第一个运用程序时,可能有人通知过你不该该用+来衔接String。如果你是在运用程序逻辑中衔接字符串,这是正确的。字符串是不可变的,每个字符串的衔接成果都存储在一个新的String目标中。这需求额定的内存,会减慢你的运用程序,特别是如果你在一个循环内衔接多个字符串的话。在这些状况下,你应该遵从技巧5并运用StringBuilder。可是,如果你仅仅将字符串分红多行来改进代码的可读性,那状况就不一样了。Query q = em.createQuery(“SELECTa.id, a.firstName, a.lastName ”+ “FROMAuthor a ”+ “WHEREa.id = :id”);在这些状况下,你应该用一个简略的+来衔接你的字符串。Java编译器会对此优化并在编译时履行衔接。所以,在运转时,你的代码将只运用1个String,不需求衔接。7.尽可能运用基元防止任何开支并进步运用程序功用的另一个简洁而快速的办法是运用根本类型而不是其包装类。所以,最好运用int来替代Integer,运用double来替代Double。这答应JVM将值存储在仓库而不是堆中以削减内存耗费,并作出更有用的处理。8.试着防止BigInteger和BigDecimal已然我们在评论数据类型,那么我们也快速阅读一下BigInteger和BigDecimal吧。特别是后者因其精确性而遭到我们的欢迎。可是这是有价值的。BigInteger和BigDecimal比简略的long或double需求更多的内存,并且会明显减慢一切核算。所以,你如果需求额定的精度,或许数字将超越long的规模,那么最好三思而后行。这可能是你需求更改以处理功用问题的仅有办法,特别是在完成数学算法的时分。9.首要查看当时日志等级这个主张应该是清楚明了的,但不幸的是,许多程序员在写代码的时分都会大多会疏忽它。在你创立调试音讯之前,一直应该首要查看当时日志等级。不然,你可能会创立一个之后会被疏忽的日志音讯字符串。这里有两个不和比如。// don’t do thislog.debug(“User [” + userName + “] called method X with [” + i + “]”);// or thislog.debug(String.format(“User [%s] called method X with [%d]”, userName, i));在上面两种状况中,你都将履行创立日志音讯一切必需的过程,在不知道日志结构是否将运用日志音讯的前提下。因而在创立调试音讯之前,最好先查看当时的日志等级。// do thisif (log.isDebugEnabled()){ log.debug(“User [” + userName + “] called method Xwith [” + i + “]”);}10.运用Apache Commons StringUtils.Replace而不是String.replace一般来说,String.replace办法作业正常,功率很高,特别是在运用Java 9的状况下。可是,如果你的运用程序需求许多的替换操作,并且没有更新到最新的Java版别,那么我们仍然有必要查找更快和更有用的替代品。有一个备选答案是Apache Commons Lang的StringUtils.replace办法。正如Lukas Eder在他最近的一篇博客文章中所描绘的,StringUtils.replace办法远胜Java 8的String.replace办法。并且它只需求很小的改动。即增加Apache Commons Lang项目的Maven依靠项到运用程序pom.xml中,并将String.replace办法的一切调用替换为StringUtils.replace办法。// replace thistest.replace(“test”,“simple test”);// with thisStringUtils.replace(test, “test”,“simple test”);11.缓存贵重的资源,如数据库衔接缓存是防止重复履行贵重或常用代码片段的盛行处理计划。总的思路很简略:重复运用这些资源比重复创立新的资源要廉价。一个典型的比如是缓存池中的数据库衔接。新衔接的创立需求时刻,如果你重用现有衔接,则能够防止这种状况。你还能够在Java言语自身找到其他比如。例如,Integer类的valueOf办法缓存了-128到127之间的值。你可能会说创立一个新的Integer并不是太贵重,可是因为它常常被运用,以至于缓存最常用的值也能够供给功用优势。可是,当你考虑缓存时,请记住缓存完成也会发作开支。你需求花费额定的内存来存储可重用资源,因而你可能需求办理缓存以使资源可拜访,以及删去过期的资源。所以,在开端缓存任何资源之前,请保证施行缓存是值得的,也就是说有必要足够多地运用它们。总结正如你所看到的,有时不需求太多作业就能够进步运用程序的功用。本文中的大部分主张只需求你稍作尽力就能够将它们运用于你的代码。可是,最重要的仍是那些与是什么编程言语无关的技巧:在你知道必要之前不要优化运用剖析器查找真实的瓶颈首要处理最大的瓶颈 |