中國大陸電動車銷量年增169% 私家車成長幅度大

大陸公安部交管局公布,截至去(2015)年底,大陸機動車保有量達2.79億輛,其中汽車1.72億輛。在新能源汽車部分,截至去年底,大陸新能源汽車保有量已達58.32萬輛,年增169.48%;其中,純電動汽車保有量33.2萬輛,占56.93%,其保有量與2014年相比增幅達317.06%。

隨著大陸經濟持續發展,民眾購車剛性需求旺盛,汽車保有量繼續呈快速增長趨勢,去年新註冊登記的汽車達2,385萬輛,保有量淨增1,781萬輛,均為歷史最高水準。汽車占機動車的比率迅速提高,近5年汽車占機動車比率從47.06%提高到61.82%。

大陸全國已有40個城市的汽車保有量超過百萬輛,北京、成都、深圳、上海、重慶、天津、蘇州、鄭州、杭州、廣州、西安等11個城市汽車保有量超過200萬輛。

截至去年底,大陸小型載客汽車達1.36億輛,其中,私家車達1.24億輛,占91.53%;與2014年相比,私家車增加1,877萬輛,增長17.77%。全國平均每百戶家庭擁有31輛私家車,北京、成都、深圳等大城市每百戶家庭擁有私家車超過60輛。

(本文內容由授權使用)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

[ASP.NET Core 3框架揭秘] 依賴注入[9]:實現概述

《》、《》和《》主要從實現原理的角度對.NET Core的依賴注入框架進行了介紹,接下來更進一步,看看該框架的總體設計和實現。在過去的多個版本更迭過程中,依賴注入框架的底層實現一直都在發生改變,加上底層的涉及的大都是內容接口和類型,所以我們不打算涉及太過細節的層面。

一、ServiceProviderEngine & ServiceProviderEngineScope

對於依賴注入的底層設計和實現來說,ServiceProviderEngine和ServiceProviderEngineScope是兩個最為核心的類型。顧名思義,ServiceProviderEngine表示提供服務實例的提供引擎,服務實例最終是通過該引擎提供的,在一個應用範圍內只存在一個全局唯一的ServiceProviderEngine對象。ServiceProviderEngineScope代表服務範圍,它利用對提供服務實例的緩存實現對生命周期的控制。ServiceProviderEngine實現了接口IServiceProviderEngine,從如下的代碼片段可以看出,一個ServiceProviderEngine對象同時也是一個IServiceProvider對象,還是一個IServiceScopeFactory對象。

internal interface IServiceProviderEngine :  IServiceProvider, IDisposable, IAsyncDisposable
{
    void ValidateService(ServiceDescriptor descriptor);
    IServiceScope RootScope { get; }
}

internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory
{
    public IServiceScope RootScope { get; }    
    public IServiceScope CreateScope();
    ...
}

ServiceProviderEngine的RootScope屬性返回的IServiceScope對象是為根容器提供的服務範圍。作為一個IServiceScopeFactory對象,ServiceProviderEngine的CreateScope會創建一個新的服務範圍,這兩種服務範圍都通過一個ServiceProviderEngineScope對象來表示。

internal class ServiceProviderEngineScope : IServiceScope, IDisposable,  IServiceProvider, IAsyncDisposable
{
    public ServiceProviderEngine Engine { get; }
    public IServiceProvider ServiceProvider { get; }
    public object GetService(Type serviceType);
}

如上面的代碼片段所示,一個ServiceProviderEngineScope對象不僅是一個IServiceScope對象,還是一個IServiceProvider對象。在《》中,我們說表示服務範圍的IServiceScope對象是對一個表示依賴注入容器的IServiceProvider對象的封裝,實際上兩者合併為同一個ServiceProviderEngineScope對象,一個ServiceProviderEngineScope對象的ServiceProvider屬性返回的就是它自己。換句話說,我們所謂的子容器和它所在的服務範圍引用的都是同一個ServiceProviderEngineScope對象。

下圖進一步揭示了ServiceProviderEngine和ServiceProviderEngineScope之間的關係。對於一個通過調用ServiceProviderEngine對象的CreateScope創建的ServiceProviderEngineScope來說,由於它同時也是一個IServiceProvider對象,如果我們調用它的GetService<IServiceProvider>方法,該方法同樣返回它自己。如果我們調用它的GetService<IServiceScopeFactory>方法,它返回創建它的ServiceProviderEngine對象,也就是該方法和Engine屬性返回同一個對象。

依賴注入框架提供的服務實例最終是通過ServiceProviderEngine對象提供的。從上面給出的代碼片段可以看出,ServiceProviderEngine是一個抽象類,.NET Core依賴注入框架提供了如下四個具體的實現類型,默認使用的是DynamicServiceProviderEngine。

  • RuntimeServiceProviderEngine:採用反射的方式提供服務實例;
  • ILEmitServiceProviderEngine:採用IL Emit的方式提供服務實例;
  • ExpressionsServiceProviderEngine:採用表達式樹的方式提供服務實例;
  • DynamicServiceProviderEngine:根據請求併發數量動態決定最終的服務實例提供方案(反射和者IL Emit或者反射與表達式樹,是否選擇IL Emit取決於當前運行時是否支持Reflection Emit)。

4.4.2. ServiceProvider

調用IServiceCollection集合的擴展方法BuildServiceProvider創建的是一個ServiceProvider對象。作為根容器的ServiceProvider對象,和前面介紹的ServiceProviderEngine和ServiceProviderEngineScope對象,一起構建了整個依賴注入框架的設計藍圖。

在利用IServiceCollection集合創建ServiceProvider對象的時候,提供的服務註冊將用來創建一個具體的ServiceProviderEngine對象。該ServiceProviderEngine對象的RootScope就是它創建的一個ServiceProviderEngineScope對象,子容器提供的Singleton服務實例由它維護。如果調用ServiceProvider對象的GetService<IServiceProvider>方法,返回的其實不是它自己,而是作為RootScope的ServiceProviderEngineScope對象(調用ServiceProviderEngineScope對象的GetService<IServiceProvider>方法返回的是它自己)。

ServiceProvider和ServiceProviderEngineScope都實現了IServiceProvider接口,如果我們調用了它們的GetService<IServiceScopeFactory>方法,返回的都是同一個ServiceProviderEngine對象。這一個特性決定了調用它們的CreateScope擴展方法都會創建一個新的ServiceProviderEngineScope對象作為子容器。綜上所述,我們針對依賴注入框架總結出如下的特性:

  • ServiceProviderEngine的唯一性:整個服務提供體系只存在一個唯一的ServiceProviderEngine對象。
  • ServiceProviderEngine與IServiceFactory的同一性:唯一存在的ServiceProviderEngine會作為創建服務範圍的IServiceFactory工廠。
  • ServiceProviderEngineScope和IServiceProvider的同一性:表示服務範圍的ServiceProviderEngineScope同時也是作為服務提供者的依賴注入容器。

為了印證我們總結出來的特性,我們編寫的測試代碼。由於設計的ServiceProviderEngine和ServiceProviderEngineScope都是內部類型,我們只能採用反射的方式得到它們的屬性或者字段成員。上面總結的這些特徵體現在如下幾組調試斷言中。

class Program
{
    static void Main()
    {
        var (engineType, engineScopeType) = ResolveTypes();
        var root = new ServiceCollection().BuildServiceProvider();
        var child1 = root.CreateScope().ServiceProvider;
        var child2 = root.CreateScope().ServiceProvider;

        var engine = GetEngine(root);
        var rootScope = GetRootScope(engine, engineType);

        //ServiceProviderEngine的唯一性
        Debug.Assert(ReferenceEquals(GetEngine(rootScope, engineScopeType), engine));
        Debug.Assert(ReferenceEquals(GetEngine(child1, engineScopeType), engine));
        Debug.Assert(ReferenceEquals(GetEngine(child2, engineScopeType), engine));

        //ServiceProviderEngine和IServiceScopeFactory的同一性
        Debug.Assert(ReferenceEquals(root.GetRequiredService<IServiceScopeFactory>(), engine));
        Debug.Assert(ReferenceEquals(child1.GetRequiredService<IServiceScopeFactory>(), engine));
        Debug.Assert(ReferenceEquals(child2.GetRequiredService<IServiceScopeFactory>(), engine));

        //ServiceProviderEngineScope提供的IServiceProvider是它自己
        //ServiceProvider提供的IServiceProvider是RootScope
        Debug.Assert(ReferenceEquals(root.GetRequiredService<IServiceProvider>(), rootScope));
        Debug.Assert(ReferenceEquals(child1.GetRequiredService<IServiceProvider>(), child1));
        Debug.Assert(ReferenceEquals(child2.GetRequiredService<IServiceProvider>(), child2));

        //ServiceProviderEngineScope和IServiceProvider的同一性
        Debug.Assert(ReferenceEquals((rootScope).ServiceProvider, rootScope));
        Debug.Assert(ReferenceEquals(((IServiceScope)child1).ServiceProvider, child1));
        Debug.Assert(ReferenceEquals(((IServiceScope)child2).ServiceProvider, child2));
    }

    static (Type Engine, Type EngineScope) ResolveTypes()
    {
        var assembly = typeof(ServiceProvider).Assembly;
        var engine = assembly.GetTypes().Single(it => it.Name == "IServiceProviderEngine");
        var engineScope = assembly.GetTypes().Single(it => it.Name == "ServiceProviderEngineScope");
        return (engine, engineScope);
    }

    static object GetEngine(ServiceProvider serviceProvider)
    {
        var field = typeof(ServiceProvider).GetField("_engine", BindingFlags.Instance | BindingFlags.NonPublic);
        return field.GetValue(serviceProvider);
    }

    static object GetEngine(object enginScope, Type engineScopeType)
    {
        var property = engineScopeType.GetProperty("Engine", BindingFlags.Instance | BindingFlags.Public);
        return property.GetValue(enginScope);
    }

    static IServiceScope GetRootScope(object engine, Type engineType)
    {
        var property = engineType.GetProperty("RootScope", BindingFlags.Instance | BindingFlags.Public);
        return (IServiceScope)property.GetValue(engine);
    }
}

三、注入IServiceProvider對象

在《》中,我們從“Service Locator”設計模式是反模式的角度說明了為什麼不推薦在服務中注入IServiceProvider對象。不過反模式並不就等於是完全不能用的模式,有些情況下直接在服務構造函數中注入作為依賴注入容器的IServiceProvider對象可能是最快捷省事的解決方案。對於IServiceProvider對象的注入,有個細節大家可能忽略或者誤解。

讀者朋友們可以試着思考這麼一個問題:如果我們在某個服務中注入了IServiceProvider對象,當我們利用某個IServiceProvider對象來提供該服務實例的時候,注入的IServiceProvider對象是它自己嗎?以如下所示的代碼片段為例,我們定義了兩個在構造函數中注入了IServiceProvider對象的服務類型SingletonService和ScopedService,並按照命名所示的生命周期進行了註冊。

class Program
{
    static void Main()
    {
        var serviceProvider = new ServiceCollection()
            .AddSingleton<SingletonService>()
            .AddScoped<ScopedService>()
            .BuildServiceProvider();
        using (var scope = serviceProvider.CreateScope())
        {
            var child = scope.ServiceProvider;
            var singletonService = child.GetRequiredService<SingletonService>();
            var scopedService = child.GetRequiredService<ScopedService>();

            Debug.Assert(ReferenceEquals(child, scopedService.RequestServices));
            Debug.Assert(ReferenceEquals(rootScope, singletonService.ApplicationServices));
        }
    }            

    public class SingletonService
    {
        public IServiceProvider ApplicationServices { get; }
        public SingletonService(IServiceProvider serviceProvider) => ApplicationServices = serviceProvider;
    }

    public class ScopedService
    {
        public IServiceProvider RequestServices { get; }
        public ScopedService(IServiceProvider serviceProvider) => RequestServices = serviceProvider;
    }
}

我們最終利用一個作為子容器的IServiceProvider對象(ServiceProviderEngineScope對象)來提供這來個服務類型的實例,並通過調試斷言確定注入的IServiceProvider對象是否就是作為當前依賴注入容器的ServiceProviderEngineScope對象。如果在Debug模式下運行上述的測試代碼,我們會發現第一個斷言是成立的,第二個則不成立

再次回到兩個服務類型的定義,SingletonService和ScopedService中通過注入IServiceProvider對象初始化的屬性分別被命名為ApplicationServices和RequestServices,意味着它們希望注入的分別是針對當前應用程序的根容器和針對請求的子容器。當我們利用針對請求的子容器來提供針對這兩個類型的服務實例時,如果注入的當前子容器的話,就與ApplicationServices的意圖不符。所以在提供服務實例的注入的IServiceProvider對象取決於採用的生命周期模式,具體策略為:

  • Singleton:注入的是ServiceProviderEngine的RootScope屬性表示的ServiceProviderEngineScope對象。
  • Scoped和Transient:如果當前IServiceProvider對象類型為ServiceProviderEngineScope,注入的就是它自己,如果是一個ServiceProvider對象,注入的還是ServiceProviderEngine的RootScope屬性表示的ServiceProviderEngineScope對象。

基於生命周期模式注入IServiceProvider對象的策略可以通過如下這個測試程序來驗證。最後還有一點需要補充一下:我們將調用IServiceCollection集合的BuildServiceProvider擴展方法創建的ServiceProvider對象作為根容器,它對應的ServiceProviderEngine對象的RootScope屬性返回作為根服務範圍的ServiceProviderEngineScope對象,ServiceProvider、ServiceProviderEngine和ServiceProviderEngineScope這三個類型全部實現了IServiceProvider接口,這三個對象都可以視為根容器。

class Program
{
    static void Main()
    {
        var serviceProvider = new ServiceCollection()
            .AddSingleton<SingletonService>()
            .AddScoped<ScopedService>()
            .BuildServiceProvider();
        var rootScope = serviceProvider.GetService<IServiceProvider>();
        using (var scope = serviceProvider.CreateScope())
        {
            var child = scope.ServiceProvider;
            var singletonService = child.GetRequiredService<SingletonService>();
            var scopedService = child.GetRequiredService<ScopedService>();

            Debug.Assert(ReferenceEquals(child, child.GetRequiredService<IServiceProvider>()));
            Debug.Assert(ReferenceEquals(child, scopedService.RequestServices));
            Debug.Assert(ReferenceEquals(rootScope, singletonService.ApplicationServices));
        }
    }
}

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

高德客戶端及引擎技術架構演進與思考

2019杭州雲棲大會上,高德地圖技術團隊向與會者分享了包括視覺與機器智能、路線規劃、場景化/精細化定位、時空數據應用、億級流量架構演進等多個出行技術領域的熱門話題。現場火爆,聽眾反響強烈。我們把其中的優秀演講內容整理成文並陸續發布出來,本文為其中一篇。

阿里巴巴高級無線開發專家宋照春在高德技術專場做了題為《高德客戶端及引擎技術架構演進與思考》的演講,主要分享了高德地圖客戶端技術架構沿着「上漂下沉」、「模塊化、Bundle化」的思路演進所做的一系列架構升級中的經驗和思考。

以下為宋照春演講內容的簡版實錄:

主要分享三個方面的內容:

  • 融合
  • 架構治理
  • 動態化

一、三管齊下 深度融合

高德最初有兩個端,車機版的高德導航,手機版的高德地圖,兩個團隊,一個是2B,一個是2C,分別是汽車業務和手機業務。當時在引擎/技術上,分為離線引擎和在線引擎,但兩個團隊之間交流比較少,各自有自己的研發、產品和測試,而作為一款端上的APP,兩塊業務都需要有地圖渲染、路線規劃、導航以及定位等通用能力。從公司層面看,存在較大的重複建設,整體研發效率較低。

於是我們做了一件事:利用技術手段,打通端上引擎,打造一套能同時支撐多端的APP能力。具體到執行層面,先從A團隊拉一部分人到B團隊一起建設,建設完之後再從B團隊拉到A團隊。在同時支撐好主線業務發展的情況下,通過一年左右時間,完成了引擎上的融合,做到同時支撐手機、車機以及開放平台。

這樣就從引擎的維度,實現了渲染、定位、規劃和引導的統一。具體來說,我們的各大引擎有好多套代碼,好幾個開發團隊,每個團隊有各自的開發方式和開發環境(Linux,Windows,Mac OS)。各種開發環境,工程配置文件大量重複,修改非常繁瑣。

為此,我們通過兩種方法:

1.建立了一套構建系統Abtor,通過一個配置系統實現統一構建,能夠同時支持多個子引擎,在構建集成效率上得到了很大的提升;

2.對基礎庫進行了整體重構,形成了一套涵蓋了文件I/O、KV存儲、多線程框架&異步框架、歸檔、基礎容器等一系列標準能力的基礎庫,同時也做了引擎核心架構的統一。

 

二、架構治理

通過引擎的融合同時支持多端,在研發效率上實現比較大的收益。而通過技術的抓手來實現團隊的融合,對公司發展而言,這其實是更大的收益,團隊融合的意義在於人才拉通和復用,組織效率得到了較大提升。

隨着高德業務的快速發展,業務上持續擴品類,需求量激增,高德地圖從最初的駕車導航,到後來的步行、騎行、摩托車導航等等,App所承載的業務發展非常快,而原有的架構治理模式的問題也逐漸暴露出來。

首先就是App的代碼規模變得特別大。當時一個倉庫達到了10G以上,由此導致的一個典型的問題就是編譯慢,編譯出一次安裝包需要一個小時。伴隨代碼規模的另一個問題是團隊規模快速增長。代碼增長和大團隊并行開發,最終導致合版慢,每次迭代,客戶端合版需要2天。

代碼膨脹導致的架構腐化問題特別突出,所以測試質量以及線上的質量有段時間也比較差。此外,從產品提出需求到上線,平均需要45天,版本迭代周期很長。

為解決以上架構問題,我們採取了三個手段:升級Native基礎組件,搭建Native容器和頁面框架,Bundle化分拆(微應用)。

下面重點介紹下頁面框架和微應用。

頁面框架主要借鑒和融合了Android和iOS的生命期管理機制。從高德地圖App架構看,下層模塊是一套標準地圖,所有上層業務都要基於地圖模塊開發。為確保上層業務低耦合、一致性,我們設計了一個頁面框架。

如上圖,左邊的Activity是Android的系統頁面控制器,右邊的UIViewController是iOS的系統頁面控制器,通過虛線連接比較,我們發現兩端的頁面狀態設計基本相同。

所以,我們在設計自己的頁面框架時沿用了這些系統頁面狀態,同時從命名上也保持一致,這樣可以讓Android和iOS原生開發的同學更容易理解和上手。

我們吸取了雙端各自的優點。比如,Android端頁面有四種啟動模式,但是iOS 端並沒有這些,我們就把Android的四種啟動模式運用到了iOS端;iOS端有Present特性,但是Android端沒有,那麼也把這種特性融合到Android端的頁面框架中;最後,還有一些小設計,比如Android的onResult設計,也可以借鑒融合到iOS端。

此外,我們還做了微應用,所謂微應用,首先是模塊化,就是把大模塊倉庫大模塊拆成一個個小的Bundle,除了實現模塊化,還主要實現以下幾個目標:

粒度:以業務為單位,以業務線為分組

編譯:二進制級別的產物,可獨立編譯、出包時鏈接

依賴:松耦合,以“服務”為導向,不關心模塊歸屬

而Native容器層面,要實現四個核心目標:路由管理、服務管理、UI生命期管理、微應用管理。

通過一年時間的Bundle化改造,高德地圖單端App完成了300多個頁面的建設,拆分了100多個Bundle。

從收益來看,總編譯時間從原來的60分鐘降低到了8分鐘,合版周期從原來的3天降到1天,需求上線周期降到了1個月以內,線上質量和測試質量都得到了極大的提升,崩潰率從萬分之八降低到十萬分之八。

三、動態化

隨着高德地圖業務發展沿着擴品類、在垂直品類做精做細,景區、酒店、銀行商鋪、充電樁等個性化定製需求凸顯,對前端展現提出了更高的要求,對“快速應變”要求也更高了。

實際上,在2015年,高德就開始做動態化。最早的時候業內就有React Native,團隊做了技術調研,發現不能完全滿足業務上的需要,尤其是性能方面。最後我們決定自研一套動態化技術。

具體來說,就是通過一個核心C++引擎,把兩端業務(Android、iOS)用一套JavaScript代碼解決,實現雙端歸一,Android實現業務動態化發布。

架構層面,最下面是高德App核心的地圖引擎,我們在上面搭建了一套動態化應用引擎,通過C++來實現。應用引擎的作用是為了承上啟下,上面承載動態化業務,下層完成地圖引擎的直接打通。眾所周知,GUI的核心是DOM樹,所以應用引擎不但要實現和JavaScript引擎的整合,還要負責DOM樹的核心邏輯計算。

其次,動態化的技術和前端Web技術一致:樣式、布局。應用引擎負責完成樣式的布局計算、DOM樹Diff、事件生成。而GUI的繪製,通過Diff事件,交由原生的Android以及iOS去完成。這樣,所有的GUI都是原生的組件。

在之上,我們搭建了一套前端框架,前端框架採用當前前端響應式框架做,前端框架之上又搭建了一套前端的UI卡片庫和UI組件庫,讓上層業務能夠更高效的開發。

而對於一些通過動態化的技術無法實現,或者性能上存在卡點的功能,我們就通過Native擴展能力來支撐,這樣,完整的動態化的業務能夠直接運行在Android以及iOS上。

 

JS去執行代碼之後,前端框架會產生虛擬的DOM樹,最後提交到C++引擎,形成C++的DOM樹。C++引擎去完成布局、樣式計算,Diff計算,將每個節點的屬性和坐標交給Android以及iOS,由Native來完成最終UI的渲染。

總體來說,動態化的特點:首先是它與主流前端框架融合,充分融合了大前端的生態;第二,性能、擴展性較好。因為採用C++實現整個核心邏輯,靜態和動態的語言綁定技術,能夠保證地圖引擎的能力能夠直接透出到上層,或者從上層能夠直接call底層的C++能力;第三,多端歸一和動態化,充分利用Native優勢,接近原生Native體驗。

動態化技術改造完成之後,雙端不一致的問題降低了90%,開發、測試成本降低30%,發版周期從T+30到T+0。

最後,總結下高德客戶端及引擎技術架構演進的幾個重要階段:第一個階段,通過在線&離線引擎的融合拉通,讓高德最核心的導航能力提到提升;第二階段,在客戶端發展成為“巨型”APP,代碼量發展到超大規模的時候,通過架構治理,滿足業務快速增長的訴求,解決大規模業務體量下的架構合理性問題,消除架構瓶頸;第三個階段通過動態化的技術,實現多端歸一,以及動態發版能力,為業務發展提供更大的助力。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

美國推出全球首個可移動光伏發電車棚

Envision Solar公司開發了全球首個可移動的光伏發電車棚系統EV ARC (Electric Vehicle Autonomous Renewable Charger),EV ARC長4.88m、寬2.74m,正好收納停車位內。該車棚配備2.5kW或3.3kW的太陽能電池,年發電量為3800~7000kWh,另外,該系統還配備了21.6kWh的蓄電池。   Envision Solar的Desmond Wheatley介紹,“ARC無需打地基和鋪設電纜等等土木施工。也無需更新變壓器和開關裝置。而且ARC的尺寸就是一個車位大小,因此設置充電樁,不會使寶貴的車位減少”。   EV ARC利用該公司開發的配備水壓控制功能、類似於托運船隻使用的拖車(名為ARC Mobility)運到目的地,設置在指定的停車場,5分鐘內就能完成充電樁的設置。   目前,穀歌已經開始使用EV ARC。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

Java程序線上故障排查

目錄

這篇文章是在公司做了不少的線上Java服務故障排查和優化之後的一個總結,可以作為一個工具清單,在分析問題的時候需要有整體思路:全局觀,先從系統層面入手,大致定位方向(內存,cpu,磁盤,網絡),然後再去分析具體的進程。

一、Linux

內存和cpu

內存和cpu問題是出問題最多的一個點,因為有些命令如top同時可以觀察到內存和cpu所以放在一起。

top命令

常用參數: -H 打印具體的線程, -p 打印某個進程 進入后 按数字1 可以切換cpu的圖形看有幾個核

下面是我的測試環境shell:

top - 14:28:49 up 7 min,  3 users,  load average: 0.08, 0.26, 0.19
Tasks: 221 total,   2 running, 219 sleeping,   0 stopped,   0 zombie
%Cpu(s):  5.1 us,  3.4 sy,  0.0 ni, 91.5 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :   985856 total,    81736 free,   646360 used,   257760 buff/cache
KiB Swap:  2094076 total,  1915196 free,   178880 used.   141592 avail Mem 

我一般重點關注的指標有:

%Cpu(s): 5.1 us, 3.4 sy, 0.0 wa

這裏可以非常直觀的看到當前cpu的負載情況,us用戶cpu佔用時間,sy是系統調用cpu佔用時間,wa是cpu等待io的時間,前面兩個比較直觀,但是第三個其實也很重要,如果wa很高,那麼你就該重點關注下磁盤的負載了,尤其是像mysql這種服務器。

load average: 0.08, 0.26, 0.19

cpu任務隊列的負載,這個隊列包括正在運行的任務和等待運行的任務,三個数字分別是1分鐘、5分鐘和15分鐘的平均值。這個和cpu佔用率一般是正相關的,反應的是用戶代碼,如果超過了內核數,表示系統已經過載。也就是說如果你是8核,那麼這個数字小於等於8的負載都是沒問題的,我看網上的建議一般這個值不要超過ncpu*2-2為好。

KiB Mem : 985856 total, 81736 free, 646360 used, 257760 buff/cache

內存佔用情況,total總內存,free空餘內存, used已經分配內存,buff/cache塊設備和緩衝區佔用的內存,因為Linux的內存分配,如果有剩餘內存,他就會將內存用於cache,這樣可以較少磁盤的讀寫提高效率,如果有應用申請內存,buff/cache這部分內存也是可用的,所以正真的剩餘內存應該是free+buff/cache

swap

線上服務器一般都是禁用狀態,所以不用看這項。

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

這一欄主要是看進程的詳情,重點是%CPU %MEM,上面看的是整個服務器的負載,這裡是每個進程的負載。還有看看S這個指標,這個代碼了進程的狀態,有時候有些進程會出現T(暫停)這個狀態。

網絡

ss

netstat的高性能版,參數都基本一致

常用參數: -n 打印数字端口號 -t tcp連接 -l 監聽端口 -a 所有端口 -p 進程號 -s 打印統計信息

ss -s示例:

Total: 1732 (kernel 1987)
TCP:   42373 (estab 1430, closed 40910, orphaned 2, synrecv 0, timewait 40906/0), ports 1924
Transport Total     IP        IPv6
*     1987      -         -        
RAW   18        9         9        
UDP   18        11        7        
TCP   1463      503       960     

可以看到整體的連接情況,如timewait過高,連接數過高等情況

然後使用ss -ntap|grep 進程號 or 端口號查看進程的連接

ping

查看時延和丟包情況

mtr

查看丟包請求

磁盤

磁盤問題在mysql服務器中非常常見,很多時候mysql服務器的CPU不高但是卻出現慢查詢日誌飆升,就是因為磁盤出現了瓶頸。還有mysql的備份策略,如果沒有監控磁盤空間,可能出現磁盤滿了服務不可用的現象。

iostat命令

常用參數: -k 用kb為單位 -d 監控磁盤 -x显示詳情 num count 每個幾秒刷新 显示次數

這個是我查看磁盤負載的主要工具,也可以显示cpu的負載,不過我一般用iostat -kdx 2 10,下面是我測試環境執行情況:

root@ubuntu:~# iostat -kdx 2 10
Linux 4.13.0-38-generic (ubuntu)    11/18/2018  _x86_64_    (1 CPU)
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda              24.75   196.05  121.66    9.75  2481.33   961.29    52.40     0.44    3.33    1.12   30.95   0.51   6.71
scd0              0.00     0.00    0.02    0.00     0.08     0.00     7.00     0.00    0.25    0.25    0.00   0.25   0.00

我一般重點關注的指標有:

  1. rkB/s和wkB/s: 分別對應讀寫速度
  2. avgqu-sz: 讀寫隊列的平均請求長度,可以類比top命令的load average
  3. await r_await w_await: io請求的平均時間(毫秒),分別是讀寫,讀和寫三個平均值。這個時間都包括在隊列中等待的時間和實際處理讀寫請求的時間,還有svctm這個參數,他說的是實際處理讀寫請求的時間,照理來講w_await肯定是大於svctm的,但是我在線上看到有w_await小於svctm的情況,不知道是什麼原因。我看iostat的man手動中說svctm已經廢棄,所以一般我看的是這三個。
  4. %util: 這個參數直觀的看磁盤的負載情況,我首先看的就是這個參數。和top的wa命令有關聯。

df

查看文件系統的容量

常用參數: -h 友好的單位 如Kb,Mb等

du

統計具體的文件大小

常用參數: -h 友好的單位 如Kb,Mb等 -s 總計,而不是進入每個子目錄分別統計

場景:例如系統磁盤空間不足時,先通過df命令定位到具體的掛載目錄,在進去掛載目錄后,使用
du -sh *查看各個文件或者子目錄的大小定位具體文件

這裏還有ls命令,可以通過加-h和-S(按大小排序)

iostat命令

常用參數: -k 用kb為單位 -d 監控磁盤 -x显示詳情 num count 每個幾秒刷新 显示次數

這個是我查看磁盤負載的主要工具,也可以显示cpu的負載,不過我一般用iostat -kdx 2 10,下面是我測試環境執行情況:

root@ubuntu:~# iostat -kdx 2 10
Linux 4.13.0-38-generic (ubuntu)    11/18/2018  _x86_64_    (1 CPU)
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda              24.75   196.05  121.66    9.75  2481.33   961.29    52.40     0.44    3.33    1.12   30.95   0.51   6.71
scd0              0.00     0.00    0.02    0.00     0.08     0.00     7.00     0.00    0.25    0.25    0.00   0.25   0.00

我一般重點關注的指標有:

  1. rkB/s和wkB/s: 分別對應讀寫速度
  2. avgqu-sz: 讀寫隊列的平均請求長度,可以類比top命令的load average
  3. await r_await w_await: io請求的平均時間(毫秒),分別是讀寫,讀和寫三個平均值。這個時間都包括在隊列中等待的時間和實際處理讀寫請求的時間,還有svctm這個參數,他說的是實際處理讀寫請求的時間,照理來講w_await肯定是大於svctm的,但是我在線上看到有w_await小於svctm的情況,不知道是什麼原因。我看iostat的man手動中說svctm已經廢棄,所以一般我看的是這三個。
  4. %util: 這個參數直觀的看磁盤的負載情況,我首先看的就是這個參數。和top的wa命令有關聯。

lsof

列出當前系統打開文件,因為在linux下一切皆是文件,連接,硬件等均被描述為文件,所以這個命令也十分有用。

常用參數:

  1. -p 查看某個進程的文件
  2. 直接加文件名 查看哪些進程打開了文件
  3. +d 目錄 查看哪些進程打開了目錄以及下面的文件(不遞歸,+D是遞歸)

Sar
最後補充一個sar(System Activity Reporter)命令,如果系統沒有一個良好的監控,那麼這個命令對於排查問題是很好的補充,很多時候去排查問題的時候發現問題已經沒了,可以通過這個命令查看系統的活動情況,比如各個時間段cpu情況,內存情況。

常用參數:

  1. -r 內存信息
  2. -q loader信息,運行隊列情況
  3. -u cpu信息
  4. -W Swap換頁情況

/proc文件系統

/proc是個虛擬文件系統,是內核的一些數據,很多linux命令的都是通過解析/proc文件系統實現的,每個進程都會有一個以pid為目錄名的子目錄存在,通過解析/proc下的進程目錄可以得到很多進程的設置信息和資源佔用信息等。

這裏簡單說個排查過的問題,當時我們線上有個服務,正常ssh登錄的情況下,我們設置了ulimit中的open files為(進程可打開的最大描述符數量)100000,但是有一次在服務的日誌中發現有報錯說文件描述符不夠用。所以

二、JVM

java -XX:+PrintFlagsInitial 可以查看所以的jvm默認參數,其中帶有manageable表示運行時可以動態修改。

20:45 [root@centos]$ java -XX:+PrintFlagsInitial |grep manageable
     intx CMSAbortablePrecleanWaitMillis            = 100                                 {manageable}
     intx CMSTriggerInterval                        = -1                                  {manageable}
     intx CMSWaitDuration                           = 2000                                {manageable}
     bool HeapDumpAfterFullGC                       = false                               {manageable}
     bool HeapDumpBeforeFullGC                      = false                               {manageable}
     bool HeapDumpOnOutOfMemoryError                = false                               {manageable}
    ccstr HeapDumpPath                              =                                     {manageable}
    uintx MaxHeapFreeRatio                          = 70                                  {manageable}
    uintx MinHeapFreeRatio                          = 40                                  {manageable}
     bool PrintClassHistogram                       = false                               {manageable}
     bool PrintClassHistogramAfterFullGC            = false                               {manageable}
     bool PrintClassHistogramBeforeFullGC           = false                               {manageable}
     bool PrintConcurrentLocks                      = false                               {manageable}
     bool PrintGC                                   = false                               {manageable}
     bool PrintGCDateStamps                         = false                               {manageable}
     bool PrintGCDetails                            = false                               {manageable}
     bool PrintGCID                                 = false                               {manageable}
     bool PrintGCTimeStamps                         = false                               {manageable}

Java堆和垃圾收集器

java內存結構

堆內存結構:

java8元空間改動:

java 7種垃圾收集器:

常見搭配:

  1. java8默認:Parallel Scavenge和 Parallel Old
  2. 低延遲:ParNew和CMS
  3. java8以後可以直接使用G1,參數比較簡單

ParNew

Serial的并行版本

Parallel Scavenge

注重的是吞吐量,吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間),其具有自適應的特性

  1. 控制最大垃圾收集停頓時間的-XX:MaxGCPauseMillis參數
    MaxGCPauseMillis參數允許的值是一個大於0的毫秒數,收集器將儘力保證內存回收花費的時間不超過設定值。不過大家不要異想天開地認為如果把這個參數的值設置得稍小一點就能使得系統的垃圾收集速度變得更快,GC停頓時間縮短是以犧牲吞吐量和新生代空間來換取的:系統把新生代調小一些,收集300MB新生代肯定比收集500MB快吧,這也直接導致垃圾收集發生得更頻繁一些,原來10秒收集一次、每次停頓100毫秒,現在變成5秒收集一次、每次停頓70毫秒。停頓時間的確在下降,但吞吐量也降下來了。

  2. 直接設置吞吐量大小的 -XX:GCTimeRatio參數
    GCTimeRatio參數的值應當是一個大於0小於100的整數,也就是垃圾收集時間佔總時間的比率。如果把此參數設置為19,那允許的最大GC時間就佔總時間的5%(即1 /(1+19)),默認值為99,就是允許最大1%(即1 /(1+99))的垃圾收集時間。

  3. UseAdaptiveSizePolicy開關參數
    -XX:+UseAdaptiveSizePolicy是一個開關參數,當這個參數打開之後,就不需要手工指定新生代的大小(-Xmn)、Eden與Survivor區的比例(-XX:SurvivorRatio)、晉陞老年代對象年齡(-XX:PretenureSizeThreshold)等細節參數了,虛擬機會根據當前系統的運行情況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或最大的吞吐量,這種調節方式稱為GC自適應的調節策略(GC Ergonomics)。

說說UseAdaptiveSizePolicy參數,加了這個參數-XX:SurvivorRatio會失效,所以有些人會發現新生代比例未如自己的預期,而UseAdaptiveSizePolicy有默認是開啟的

CMS

併發垃圾收集器,注重的是時延,有分配擔保失敗的風險

CMS收集器的GC周期由6個階段組成。其中4個階段(名字以Concurrent開始的)與實際的應用程序是併發執行的,而其他2個階段需要暫停應用程序線程。

初始標記:為了收集應用程序的對象引用需要暫停應用程序線程,該階段完成后,應用程序線程再次啟動。
併發標記:從第一階段收集到的對象引用開始,遍歷所有其他的對象引用。
併發預清理:改變當運行第二階段時,由應用程序線程產生的對象引用,以更新第二階段的結果。
重標記:由於第三階段是併發的,對象引用可能會發生進一步改變。因此,應用程序線程會再一次被暫停以更新這些變化,並且在進行實際的清理之前確保一個正確的對象引用視圖。這一階段十分重要,因為必須避免收集到仍被引用的對象。
併發清理:所有不再被應用的對象將從堆里清除掉。
併發重置:收集器做一些收尾的工作,以便下一次GC周期能有一個乾淨的狀態。

  1. -XX:CMSInitiatingOccupancyFraction=90 (jdk1.5默認值68,1.6開始默認值92,指設定CMS在對內存佔用率達到70%的時候開始GC(因為CMS會有浮動垃圾,所以一般都較早啟動GC)
  2. -XX:+UseCMSInitiatingOccupancyOnly 只是用設定的回收閾值(上面指定的70%),如果不指定,JVM僅在第一次使用設定值,後續則自動調整
  3. -XX:+CMSScavengeBeforeRemark 在CMS GC前啟動一次ygc,目的在於減少old gen對ygc gen的引用,降低remark時的開銷
  4. -XX:+CMSParallelRemarkEnabled 併發標記
  5. -XX:+ExplicitGCInvokesConcurrent命令JVM無論什麼時候調用系統GC(system.gc()),都執行CMS GC,而不是Full GC
  6. -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses保證當有系統GC調用時,永久代也被包括進CMS垃圾回收的範圍內
  7. -XX:UseParNewGC 使用CMS時自動開啟,因為CMS不能和Parallel Scavenge搭配使用

上面的參數都建議開啟,CMS需要注意的一個問題就是CMSInitiatingOccupancyFraction參數,這個參數直接影響CMS回收老年代的時機,需要結合自己的業務場景來調整,一般情況下應該盡量設置大一點,但是有一個嚴重的問題,就是浮動垃圾的問題,如果CMS在併發收集的時候出現老年代不能存放晉陞對象將直接進行Full GC使用Serial Old垃圾收集器,所以不能一味追求最大化,如果老年代增長比較慢,那麼可以設置的稍微較大些,如果增長比較快,可以從增大新生代,調低CMSInitiatingOccupancyFraction入手

最後在提下-XX:+DisableExplicitGC :禁用显示gc (system.gc())這個參數,很多人因為system.gc()會導致Full gc而禁用显示調用gc,但是這個參數最好不要禁用,現在很多服務端程序都使用了Nio,jvm為了減少內存拷貝,採用了直接內存,直接內存屬於堆外內存,java大多使用了Netty這個框架,他幫我們處理堆外內存的回收,實現的機制就是通過調用system.gc(),發起Full Gc,Full Gc會回收堆外內存,如果將system.gc()禁用,則得等到Full Gc發生才能回收堆外內存,很有可能出現堆外內存佔用過高影響系統性能或者因為內存不足被系統Kill的問題。

gc日誌參數

  1. -XX:+PrintGC 輸出GC日誌
  2. -XX:+PrintGCDetails 輸出GC的詳細日誌
  3. -XX:+PrintGCTimeStamps 輸出GC的時間戳(以基準時間的形式)
  4. -XX:+PrintGCDateStamps 輸出GC的時間戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
  5. -XX:+PrintHeapAtGC 在進行GC的前後打印出堆的信息
  6. -XX:+PrintGCApplicationStoppedTime // 輸出GC造成應用暫停的時間
  7. -Xloggc:../logs/gc.log 日誌文件的輸出路徑
  8. -XX:+PrintTenuringDistribution 打印新生代的年齡分佈(這裏需要注意,如果使用的是Parallel Scavenge,那麼打印的時候是沒有年齡分佈信息的)
  9. -XX:+UseGCLogFileRotation 開啟日誌輪換
  10. -XX:NumberOfGCLogFiles=5 日誌保留數量
  11. -XX:GCLogFileSize=10m 每份日誌保留大小

堆參數

  1. -Xms 最小堆大小
  2. -Xmx 最大堆大小
  3. -Xmn 新生代大小
  4. -XX:SurvivorRatio 新生代中Eden區與Survivor區的比例,默認值為8

gc日誌分析

ParNew Gc日誌:

{Heap before GC invocations=4196 (full 3):
 par new generation   total 1887488K, used 1683093K [0x0000000640000000, 0x00000006c0000000, 0x00000006c0000000)
  eden space 1677824K, 100% used [0x0000000640000000, 0x00000006a6680000, 0x00000006a6680000)
  from space 209664K,   2% used [0x00000006a6680000, 0x00000006a6ba5430, 0x00000006b3340000)
  to   space 209664K,   0% used [0x00000006b3340000, 0x00000006b3340000, 0x00000006c0000000)
 concurrent mark-sweep generation total 4194304K, used 1565111K [0x00000006c0000000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 59881K, capacity 64953K, committed 66588K, reserved 1107968K
  class space    used 6615K, capacity 7729K, committed 8224K, reserved 1048576K
2019-10-29T23:48:00.181+0800: 27966.548: [GC (Allocation Failure) 2019-10-29T23:48:00.181+0800: 27966.548: [ParNew
Desired survivor size 107347968 bytes, new threshold 15 (max 15)
- age   1:    2287832 bytes,    2287832 total
- age   2:     132752 bytes,    2420584 total
- age   3:     102408 bytes,    2522992 total
- age   4:     125768 bytes,    2648760 total
- age   5:     145464 bytes,    2794224 total
- age   6:      82808 bytes,    2877032 total
- age   7:     104736 bytes,    2981768 total
- age   8:      79216 bytes,    3060984 total
- age   9:      89496 bytes,    3150480 total
- age  10:      81864 bytes,    3232344 total
- age  11:      91304 bytes,    3323648 total
- age  12:      78912 bytes,    3402560 total
- age  13:      80960 bytes,    3483520 total
- age  14:      91560 bytes,    3575080 total
- age  15:      78992 bytes,    3654072 total
: 1683093K->5343K(1887488K), 0.0342117 secs] 3248204K->1570530K(6081792K), 0.0343754 secs] [Times: user=0.17 sys=0.01, real=0.03 secs]
Heap after GC invocations=4197 (full 3):
 par new generation   total 1887488K, used 5343K [0x0000000640000000, 0x00000006c0000000, 0x00000006c0000000)
  eden space 1677824K,   0% used [0x0000000640000000, 0x0000000640000000, 0x00000006a6680000)
  from space 209664K,   2% used [0x00000006b3340000, 0x00000006b3877f50, 0x00000006c0000000)
  to   space 209664K,   0% used [0x00000006a6680000, 0x00000006a6680000, 0x00000006b3340000)
 concurrent mark-sweep generation total 4194304K, used 1565186K [0x00000006c0000000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 59881K, capacity 64953K, committed 66588K, reserved 1107968K
  class space    used 6615K, capacity 7729K, committed 8224K, reserved 1048576K
}

gc日誌中打印了新生代,老年代和元空間等內存信息,其中Times: user=0.02 sys=0.01, real=0.01 secs三個時間分別是用戶態的時間,內核態的時間和牆鍾時間。牆鍾時間表示真正過去的時間,而用戶態和內核態的時間則是乘了相應的cpu核心數。

CMS GC日誌:

2019-10-29T18:03:19.578+0800: 7285.945: [GC (CMS Initial Mark) [1 CMS-initial-mark: 3182477K(4194304K)] 3254261K(6081792K), 0.0044508 secs] [Times: user=0.01 sys=0.01, real=0.00 secs]
2019-10-29T18:03:19.582+0800: 7285.949: [CMS-concurrent-mark-start]
2019-10-29T18:03:20.812+0800: 7287.179: [CMS-concurrent-mark: 1.229/1.229 secs] [Times: user=3.86 sys=0.46, real=1.23 secs]
2019-10-29T18:03:20.812+0800: 7287.179: [CMS-concurrent-preclean-start]
2019-10-29T18:03:20.823+0800: 7287.190: [CMS-concurrent-preclean: 0.011/0.011 secs] [Times: user=0.03 sys=0.01, real=0.01 secs]
2019-10-29T18:03:20.823+0800: 7287.190: [CMS-concurrent-abortable-preclean-start]
{Heap before GC invocations=896 (full 3):
 par new generation   total 1887488K, used 1747877K [0x0000000640000000, 0x00000006c0000000, 0x00000006c0000000)
  eden space 1677824K, 100% used [0x0000000640000000, 0x00000006a6680000, 0x00000006a6680000)
  from space 209664K,  33% used [0x00000006a6680000, 0x00000006aaae9780, 0x00000006b3340000)
  to   space 209664K,   0% used [0x00000006b3340000, 0x00000006b3340000, 0x00000006c0000000)
 concurrent mark-sweep generation total 4194304K, used 3182477K [0x00000006c0000000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 60431K, capacity 66281K, committed 66588K, reserved 1107968K
  class space    used 6828K, capacity 8138K, committed 8224K, reserved 1048576K
2019-10-29T18:03:25.649+0800: 7292.016: [GC (Allocation Failure) 2019-10-29T18:03:25.649+0800: 7292.016: [ParNew
Desired survivor size 107347968 bytes, new threshold 15 (max 15)
- age   1:    1362152 bytes,    1362152 total
- age   3:     124920 bytes,    1487072 total
- age   4:     115256 bytes,    1602328 total
- age   5:     165000 bytes,    1767328 total
- age   6:      99776 bytes,    1867104 total
- age   7:      97728 bytes,    1964832 total
- age   8:      94616 bytes,    2059448 total
- age   9:      93176 bytes,    2152624 total
- age  10:     111352 bytes,    2263976 total
- age  11:     127800 bytes,    2391776 total
- age  12:      85248 bytes,    2477024 total
- age  13:     110984 bytes,    2588008 total
- age  14:     101880 bytes,    2689888 total
- age  15:      96288 bytes,    2786176 total
: 1747877K->18163K(1887488K), 0.0364969 secs] 4930355K->3200776K(6081792K), 0.0366162 secs] [Times: user=0.17 sys=0.00, real=0.04 secs]
Heap after GC invocations=897 (full 3):
 par new generation   total 1887488K, used 18163K [0x0000000640000000, 0x00000006c0000000, 0x00000006c0000000)
  eden space 1677824K,   0% used [0x0000000640000000, 0x0000000640000000, 0x00000006a6680000)
  from space 209664K,   8% used [0x00000006b3340000, 0x00000006b44fcd88, 0x00000006c0000000)
  to   space 209664K,   0% used [0x00000006a6680000, 0x00000006a6680000, 0x00000006b3340000)
 concurrent mark-sweep generation total 4194304K, used 3182613K [0x00000006c0000000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 60431K, capacity 66281K, committed 66588K, reserved 1107968K
  class space    used 6828K, capacity 8138K, committed 8224K, reserved 1048576K
}
 CMS: abort preclean due to time 2019-10-29T18:03:25.825+0800: 7292.192: [CMS-concurrent-abortable-preclean: 4.952/5.002 secs] [Times: user=10.51 sys=1.44, real=5.01 secs]
2019-10-29T18:03:25.826+0800: 7292.193: [GC (CMS Final Remark) [YG occupancy: 81039 K (1887488 K)]2019-10-29T18:03:25.826+0800: 7292.194: [Rescan (parallel) , 0.0142974 secs]2019-10-29T18:03:25.841+0800: 7292.208: [weak refs processing, 0.0019208 secs]2019-10-29T18:03:25.843+0800: 7292.210: [class unloading, 0.0230836 secs]2019-10-29T18:03:25.866+0800: 7292.233: [scrub symbol table, 0.0054818 secs]2019-10-29T18:03:25.871+0800: 7292.238: [scrub string table, 0.0707817 secs][1 CMS-remark: 3182613K(4194304K)] 3263652K(6081792K), 0.1182958 secs] [Times: user=0.17 sys=0.01, real=0.11 secs]
2019-10-29T18:03:25.946+0800: 7292.313: [CMS-concurrent-sweep-start]
2019-10-29T18:03:27.771+0800: 7294.138: [CMS-concurrent-sweep: 1.825/1.826 secs] [Times: user=3.98 sys=0.52, real=1.82 secs]
2019-10-29T18:03:27.771+0800: 7294.138: [CMS-concurrent-reset-start]
2019-10-29T18:03:27.781+0800: 7294.148: [CMS-concurrent-reset: 0.010/0.010 secs] [Times: user=0.02 sys=0.01, real=0.01 secs]

JVMTI介紹

JVM相關參數:

 -agentlib:<庫名>[=<選項>]
                  加載本機代理庫 <庫名>, 例如 -agentlib:jdwp
                  另請參閱 -agentlib:jdwp=help
-agentpath:<路徑名>[=<選項>]
                  按完整路徑名加載本機代理庫
-javaagent:<jar 路徑>[=<選項>]
                  加載 Java 編程語言代理, 請參閱 java.lang.instrument

JVMTI(Java Virtual Machine Tool Interface)即指Java虛擬機工具接口,它是一套由虛擬機直接提供的 native 接口,通過這些接口,開發人員不僅調試在該虛擬機上運行的 Java 程序,還能查看它們運行的狀態,設置回調函數,控制某些環境變量(JMX),從而優化程序性能。Java Agent就是基於JVMTI的,所以眾多基於Java Agent的技術例如APM,遠程調試,各種性能剖析同樣是基於這個技術。

JVMTI 接口:

JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options, void *reserved);

JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM* vm, char* options, void* reserved);

JNIEXPORT void JNICALL
Agent_OnUnload(JavaVM *vm); 

-agentpath是c/c++編寫的動態庫,-agentlib和-javaagent是一個instrument的JVMTIAgent(linux下對應的動態庫是libinstrument.so)。

Attach機制

Jvm提供一種jvm進程間通信的能力,能讓一個進程傳命令給另外一個進程,並讓它執行內部的一些操作,比如說我們為了讓另外一個jvm進程把線程dump出來,那麼我們跑了一個jstack的進程,然後傳了個pid的參數,告訴它要哪個進程進行線程dump。

Attach命令列表

static AttachOperationFunctionInfo funcs[] = {
  { "agentProperties",  get_agent_properties },
  { "datadump",         data_dump },
  { "dumpheap",         dump_heap },
  { "load",             JvmtiExport::load_agent_library },
  { "properties",       get_system_properties },
  { "threaddump",       thread_dump },
  { "inspectheap",      heap_inspection },
  { "setflag",          set_flag },
  { "printflag",        print_flag },
  { "jcmd",             jcmd },
  { NULL,               NULL }
};

Attach流程:

Jstack源碼:
https://android.googlesource.com/platform/libcore/+/0ebbfbdbca73d6261a77183f68e1f3e56c339f9f/ojluni/src/main/java/sun/tools/jstack/JStack.java

查看java線程:

其中Siginal Dispatcher是處理進程信號的線程,Attach Listener正式Attach機制處理線程。

java自帶工具

jps

查看Java進程列表

常用參數:

  1. -l: 輸出應用程序主類完整package名稱或jar完整名稱
  2. -m:輸出主函數傳入的參數

jmap

查看JVM堆的情況

常用參數:

  1. -heap
  2. -dump 這個命令還有兩個常用參數
    1. live 只dump存活對象,會導致GC
    2. file=file dump文件名

示例:jmap -dump:live,file=heap.dump <pid>

這裡有兩點,一方面需要注意live會導致GC,有時候在查問題的時候可能不是你預期的效果,一般查內存問題時不加這個選項,另外dump文件如果比較大,可以先壓縮在傳回本地

jstack

查看JVM的堆棧情況,監測死鎖等

這個命令比較簡單,一般不用加什麼參數,有時候JVM沒響應時可以加-F參數。一般這個命令可以結合top,在top定位到佔用cpu高的線程后,在具體在Jstack打印的堆棧中查看線程,有時候也需要多次打印堆棧來進行對比

jstat

查看JVM gc信息,觀察JVM的GC活動

常用參數: -gccause 這個參數包含了-gcutil的信息多了一個gc原因

示例: jstat -gccause <pid> 1000

11:19 [supertool@y051]$ jstat -gccause  10711 1000
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC                 
  0.00  21.23  95.99  69.88  91.56  82.62   1187   22.511     4    0.141   22.652 Allocation Failure   No GC               
  0.00  21.23  99.51  69.88  91.56  82.62   1187   22.511     4    0.141   22.652 Allocation Failure   No GC               
 21.30   0.00   3.51  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               
 21.30   0.00   7.02  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               
 21.30   0.00  10.14  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               
 21.30   0.00  13.62  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               
 21.30   0.00  16.78  69.88  91.56  82.62   1188   22.530     4    0.141   22.671 Allocation Failure   No GC               

jinfo

查看設置的JVM參數和啟動時的命令行參數,還可以動態修改JVM參數

常用參數

  1. -flags 查看jvm參數值
  2. -sysprops 查看系統屬性值

示例:jinfo -flags 10711

Non-default VM flags: -XX:BiasedLockingStartupDelay=0 -XX:CICompilerCount=4 -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=75 -XX:+CMSParallelRemarkEnabled -XX:ErrorFile=null -XX:GCLogFileSize=10485760 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=null -XX:InitialHeapSize=1073741824 -XX:MaxHeapSize=1073741824 -XX:MaxNewSize=268435456 -XX:MaxTenuringThreshold=15 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=268435456 -XX:NumberOfGCLogFiles=20 -XX:OldPLABSize=16 -XX:OldSize=805306368 -XX:+PrintClassHistogram -XX:+PrintCommandLineFlags -XX:+PrintConcurrentLocks -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:StringTableSize=6000000 -XX:+UseBiasedLocking -XX:+UseCMSInitiatingOccupancyOnly -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseFastUnorderedTimeStamps -XX:+UseGCLogFileRotation -XX:+UseParNewGC 
Command line:  -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 -XX:+PrintCommandLineFlags -Xms1g -Xmx1g -Xmn256m -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -Dfile.encoding=UTF-8 -XX:MaxTenuringThreshold=15 -XX:StringTableSize=6000000  -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC -XX:+PrintClassHistogram -XX:+PrintConcurrentLocks -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=20 -XX:GCLogFileSize=10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/java/logs -XX:ErrorFile=/var/java/logs/jvm-error.log -Dlog4j.config.file=log4j_.properties -Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.Log4jLogDelegateFactory -Dvertx.options.maxEventLoopExecuteTime=100000000 -Dvertx.options.warningExceptionTime=300000000 

JDPA(Java Platform Debugger Architecture)

java遠程調試,需要jvm啟動時加參數:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005

遠程調試非常有用,有時候測試環境很難復現時,可以用通過遠程調試查看線程數據

三、三方工具

jprofile

CPU性能分析

抽樣:每隔一段時間,獲取線程棧,分析各個棧上出現的方法的次數

優點:性能高
缺點: 不適合做精確的分析
適用範圍:尋找程序的執行熱點,cpu密集型

指令插入:使用增強的技術修改java class的字節碼,在函數的出入口增加埋點

優點:數據準確
缺點:導致jvm內聯優化失效,性能低
適用範圍:分析具體耗時路徑的各個執行時間,io密集型

一般先使用抽樣在定位到大致的範圍,然後使用指令插入分析具體代碼執行路徑中的耗時,jprofile可以通過過濾只對指定類進行增強

  1. Thread Status:選擇線程統計狀態,Runnable显示的是cpu時間,不包含sleep這種時間一般都是這個模式。還可以使用IO Net模式分析io等待,Wait分析鎖競爭模式
  2. Call tree filters :調用樹過濾:用於過濾不需要的類,例如你使用web框架,棧中起始的方法都是框架中的代碼,最後才是你的業務代碼,這時候可以使用Call tree filters來過濾不需要的類型,減少統計造成的性能開銷

內存剖析

分析內存泄漏的利器,主要是看內存中內存佔比和大對象。很多時候如果有內存泄漏基本都是以為某些類型的對象佔用了大頭。

arthas (類似btrace的工具)

Arthas 是Alibaba開源的Java診斷工具。線上debug的工具,很多時候因為性能和安全等原因我們不能直接遠程調試線上的jvm,這時候我們可以使用arthas來查看內存的數據,方法調用情況,打印日誌信息等。

比較常用的:

  1. watch 看方法調用情況 -c 統計周期,默認值為120秒
  2. monitor 統計方法調用信息
  3. getstatic 查看靜態變量
  4. logger 查看和修改logger
  5. trace 方法內部調用路徑,並輸出方法路徑上的每個節點上耗時

示例:

  1. monitor -c 5 com.miaozhen.bazaro.deal.PreferredDealFilterService filter
  2. watch com.miaozhen.bazaro.share.manager.util.DealManager getDspToDealsByPid "returnObj"

gceasy

https://gceasy.io/ 一個在線分析gc日誌的網站,

四、實際案例

連接泄漏

場景描述:我們公司的用戶服務對接了第三方騰訊雲通信服務,在用戶註冊的時候我們需要走http接口調騰訊雲,問題就出在http連接那塊,同事當時採用了,線上出現了cpu100%的問題,日誌出現java.lang.OutOfMemoryError: GC overhead limit exceeded。

排查思路:這個其實很好定位,本來還想打印線程棧看下到底是哪個導致的cpu100%,一看日誌直接定位到gc出問題。GC overhead limit exceeded是指gc佔用了大量的cpu時間又回收不了內存引起的,從內存泄露去考慮,重啟服務 ,啟動參數加上-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./user.hprof -verbose:gc -Xloggc:user%t.log。問題復現的時候獲得了堆的dump文件,然後通過Jprofile分析,發現有大量的http.HttpKeepAliveCache實例,佔用了80%的內存,大致定位到是由於http連接泄露。同事封裝的HttpUtil中使用了HttpsURLConnection,在讀取完數據的時候沒有關閉InputStream導致連接沒有關閉。

說明:GC overhead limit exceeded,默認情況下,如果Java進程花費98%以上的時間執行GC,並且每次只有不到2%的堆被恢復,則JVM拋出此錯誤。這個錯誤是parallel Scavenge 特有的

String拼接導致內存溢出

公司的後台有段時間會間歇性的卡頓,嚴重的情況下會導致cpu100%。在cpu100%的時候,通過top定位到進程號,然後輸入H切換到線程,記住具體的進程號,使用jstack打印java進程的線程棧,jstack輸出為十六進制,需要將top的轉換成十六進制的然後入找線程經常卡在哪個方法。定位到方法發現是查詢用戶關聯設備號的方法出問題,方法的邏輯是從數據庫查詢設備號,在內存中以以逗號分隔拼接返回,如1,2,3。這個bug的原因是有如下:

sql出錯,導致查詢返回數據量很多,正常情況最多幾百個,但是異常情況有七萬個設備號
字符串拼接採用str+=”1234″的形式,導致大量的內存分配和回收。
運營在點擊後台查詢的時候發現沒返回,點掉就重新點,導致服務器多個線程卡在這個方法造成cpu100%。解決完sql,改用StringBuilder問題解決。

堆內存佔用過大

我們的一個服務程序,老年代設置了10g,新生代2g,偶會會出現內存溢出的線程,通過分析內存發現deal數據佔用了大量內存,最高可達9.4g。

堆數據:

問題代碼:

優化后堆數據:

優化后降低了老年代改為4g,大大降低了Jvm的堆的大小,16g機器現在可部署兩個實例,且Full Gc穩定在一天一次,Young Gc 5s一次,均處正常。

CPU佔用高問題

最近在分析拍賣程序時,發現com.miaozhen.bazaro.deal.PreferredDealFilterService#filter方法佔用了90%的cpu時間。

cpu熱點圖:

問題代碼:

分析該方法的時長:

查看耗時deal數據

aerospike線程阻塞導致內存溢出問題

問題:拍賣在五點多收到網站推送數據的時候發生OOM。

查看日誌發現,有很多關於線程阻塞的報錯,是讀取aerospike卡住導致。報錯如下:

觀察gc分析結果:

可以看到本來堆內存始終穩定在一個水平,在一個時間點之後,堆內存開始穩步上漲,十分符合內存泄漏的特徵。

觀察堆內存數據:

注:這個堆內存不是當時,當時的堆內存沒找到,佔比是類似的。這個圖內存優化之後的,所以老年代只有4g。

可以看到其中OrderedExecutor佔用了大量的內存,這個數據接口是用來存放http請求的接口。

總結:

晚上九點40線程阻塞,但是請求的任務不停地往他的tasks裏面放,十分鐘后grafana監控显示上升了16%的超時率(六個verticle掛了一個),從4%到20%。
查看內存監控圖,9點40開始內存上升,不再回收,最終存了2900萬個tasks,一個線程佔用了10g內存,到晚上11.15左右日誌出現大量的空指針和超時,十分鐘后監控圖显示全部超時,gc監控显示大量full gc,因為內存不夠大量的gc佔用了進程cpu時間。,5點多的時候推送物料,服務器內存溢出。

參考資料:

問題

  1. 什麼樣的代碼算是耗時的代碼,或者說耗時代碼的特徵是什麼
  2. jvm一個線程發生OOM會導致JVM掛掉嗎
  3. 內存問題會導致cpu飆高嗎

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

納智捷LUXGEN推電動車版S3房車

納智捷(LUXGEN)全力搶攻小車市場,在2015台北國際新車大展上以「智能與電能」為主題,正式推出電動車S3 EV+,造型與汽油版的S3 Turbo大致相同。同時展出的還有S5、U7、U6、M7 TURBO ERO HYPER與V7 TURBO等車款。

在十位LUXGEN Girls「十全十美」的陣容下,納智捷在台北新車大展舉行之前預先舉辦展示活動。LUXGEN將成立科技互動體驗區,帶領參展民眾親身體驗虛擬實境的感受。

S3 EV+ 本次首度亮相,以LUXGEN旗下最小型的房車S3為設計藍本。LUXGEN先前已透露2016年第二季將推出首款小型入門車S3 Turbo,搭配1.5升直列四缸全鋁合金汽油引擎、日本Aisin六速手自排變速箱,油耗最低可達每公升行駛17公里。S3 EV+ 之造型與S3 Turbo相似,但具體規格還未公告。

今年的台北新車大展將於12月25日於台北世貿一館舉行。

(照片來源:LUXGEN)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

Java nio 空輪詢bug到底是什麼

編者注:Java nio 空輪詢bug也就是Java nio在Linux系統下的epoll空輪詢問題。

epoll機制是Linux下一種高效的IO復用方式,相較於select和poll機制來說。其高效的原因是將基於事件的fd放到內核中來完成,在內核中基於紅黑樹+鏈表數據結構來實現,鏈表存放有事件發生的fd集合,然後在調用epoll_wait時返回給應用程序,由應用程序來處理這些fd事件。

使用IO復用,Linux下一般默認就是epoll,Java NIO在Linux下默認也是epoll機制,但是JDK中epoll的實現卻是有漏洞的,其中最有名的java nio epoll bug就是即使是關注的select輪詢事件返回數量為0,NIO照樣不斷的從select本應該阻塞的Selector.select()/Selector.select(timeout)中wake up出來,導致CPU 100%問題。如下圖所示:

那麼產生這個問題的原因是什麼的?其實在 上已經說明的很清楚了,比如下面是bug復現的一個場景:

A DESCRIPTION OF THE PROBLEM :
The NIO selector wakes up infinitely in this situation..
0. server waits for connection
1. client connects and write message
2. server accepts and register OP_READ
3. server reads message and remove OP_READ from interest op set
4. client close the connection
5. server write message (without any reading.. surely OP_READ is not set)
6. server's select wakes up infinitely with return value 0

上面的場景描述的問題就是連接出現了RST,因為poll和epoll對於突然中斷的連接socket會對返回的eventSet事件集合置為POLLHUP或者POLLERR,eventSet事件集合發生了變化,這就導致Selector會被喚醒,進而導致CPU 100%問題。根本原因就是JDK沒有處理好這種情況,比如SelectionKey中就沒定義有異常事件的類型。

class SelectionKey {
    public static final int OP_READ = 1 << 0;
    public static final int OP_WRITE = 1 << 2;
    public static final int OP_CONNECT = 1 << 3;
    public static final int OP_ACCEPT = 1 << 4;
}

既然nio epoll bug存在,那麼能不能規避呢?答案是有的,比如netty就很巧妙的規避了這個問題,它的處理機制就是如果發生了這種情況,並且發生次數超過了SELECTOR_AUTO_REBUILD_THRESHOLD(默認512),則調用rebuildSelector()進行Selecttor重建,這樣就不用管之前發生了異常情況的那個連接了。因為重建也是根據SelectionKey事件對應的連接來重新註冊的。

該問題最早在 Java 6 發現,隨後很多版本聲稱解決了該問題,但實際上只是降低了該 bug 的出現頻率,目前從網上搜索到的資料显示,Java 8 還是存在該問題()。

最後一起來分析下,nio epoll bug不是linux epoll的問題,而是JDK自己實現epoll時沒有考慮這種情況,或者說因為其他系統不存在這個問題,Java為了封裝(比如SelectionKey 中的4個事件類型)的統一而沒去處理?

這裏思考下,如果想要從java nio層面上來解決這個問題,該如何做呢?

一種是nio事件類型SelectionKey新加一種”錯誤”類型,比如針對linux epoll中的epollhup和epollerr,如果出現這種事件,建議程序直接close socket,但這種方式相對來說對於目前的nio SelectionKey改動有點大,因為SelectionKey的定義目前是針對所有jdk平台的;還有一種是針對jdk nio 對epoll的封裝中,對於epoll的epollhup和epollerr事件,epoll封裝內部直接處理,比如close socket,但是這種方案也有一點尷尬的是,可能上層應用代碼還保留有出現問題的socket引用,這時最好是應用程序能夠感知這種情況來處理比較好。

Java nio空轉問題由來已久,一般程序中是通過新建Selector的方式來屏蔽掉了JDK5/6的這個問題,因此,對於開發者來講,還是盡量將JDK的版本更新到最新,或者使用NIO框架如Netty,Grizzly等進行研發,以免出更多的問題。

推薦閱讀

歡迎小夥伴關注【TopCoder】閱讀更多精彩好文。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

第六屆中國國際新能源汽車論壇2016打造行業規模最大,最國際化的新能源汽車論壇

2016年4月20-22日∣中國•上海

誰能智造未來-技術應用與新熱點

隨著全球能源危機的加重及汽車排放引起的環境問題日益得到世界各國的重視,發展環保節能的汽車已經成為全球汽車行業的必然趨勢。

在過去五屆新能源汽車論壇成功舉辦的基礎上,由希邁商務諮詢(上海)有限公司主辦的2016年第六屆中國國際新能源汽車論壇即將於4月20日-4月22日在上海隆重舉行。新能源汽車系列論壇成功邀請了包括國家發改委能源研究所、世界電動車協會、亞太電動車協會、世界氫能協會、世界分散式能源聯盟、中國工程院等在內的政府單位與研究機構,以及包括寶馬、賓士、奇瑞捷豹路虎、大眾、奧迪、比亞迪、上汽、北汽等在內的知名整車商,共同研討新能源汽車行業政策趨勢、技術路線及難點、基礎設施建設、商業模式等並取得了豐碩的成果,獲得了業內外人士的一致好評。

在即將到來的2016年,組委會為感謝業內外人士對系列論壇長期以來的支援和關注,將傾情奉上相比歷屆舉辦規模最大的第六屆新能源汽車論壇,涉及三個考察活動,主論壇及三個分論壇。屆時將誠邀全球範圍內的整車製造商、電網電力公司、電池廠商、零部件供應商、核心技術提供商和政府官員近500位行業人士一起,對新能源汽車產業面臨的挑戰,機遇與對策各方面進行為期三天更深層次並具有建設和戰略性的探討。

部份往屆演講嘉賓

會議亮點

豐富的內容:
8大板塊的深度解析

參會嘉賓:
500+高度滿意的企業決策者,120+業內知名企業,30+國家和地區

參會嘉賓分析:
17%+來自各國政府部門及權威機構,25%+來自知名整車商

演講嘉賓:
40+世界新能源汽車行業知名發言嘉賓

交流機會:
16+小時的交流機會:圓桌討論、VIP午宴和開放式問答

會議形式:
1個主論壇,1個晚宴,3個分論壇以及一天3個考察活動

會議結構

若您對峰會有更多要求,請撥打021-6045 1760與我們聯繫,謝謝理解和支持!
我們期待與貴單位一起出席於2016年4月20-22日在上海舉辦的第六屆中國國際新能源汽車論壇2016,以利決策!
想瞭解詳細內容,請登陸官方網站:
連絡人:Hill ZENG(曾先生)
電話:0086 21-6045 1760
傳真:0086 21-6047 5887
郵箱:

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

氫燃料電池車軍事價值高,美國陸軍與雪佛蘭聯手測試

氫燃料電池車往往主打排放的廢氣中只有水,無一般內燃機引擎汽車的碳氫化合物、氮氧化物等等有害人體的空氣污染,不過,沒有引擎聲響,又會排出水,讓氫燃料電池車更適用於軍事用途,美國陸軍就看上了這點,與通用汽車(GM)聯手,以通用旗下雪佛蘭(Chevrolet)科羅拉多(Colorado)中型貨卡車改裝測試氫燃料電池車的軍事用途。

美國陸軍坦克車輛研發工程中心(Tank Automotive Research, Development and Engineering Center,TARDEC)表示,氫燃料電池車因為沒有引擎而相當安靜,而不論是斥侯、特戰部隊及其他專業軍種,都很重視行動匿蹤匿聲,更重要的一點是,氫燃料電池車產生的廢棄物是純水,在軍事行動中,往往需經過缺乏水源的區域,車輛自己就會產水,對在嚴峻環境執行任務有莫大幫助。   此外,氫燃料電池車可產生強大扭力,也適合在越野環境下執行任務。同時,燃料電池不僅能驅動車輛,還能同時充當其他攜帶式電子作戰裝置的電源,士兵們就不用在攜帶燃料的同時還要另外攜帶電池。   TARDEC 打算與通用汽車合作,測試一輛改裝為氫燃料電池為動力總成的雪佛蘭科羅拉多中型貨卡車,進行 12 個月的極端軍事測試,考驗它是否能勝任嚴酷的軍事需求。但 TARDEC 不願透露將如何測試車輛的詳細過程。   日本政府與豐田汽車正全力推廣氫燃料電池車,不過目前商用市場上仍有相當多障礙,如今無聲又會產水的特性先被美國陸軍看上,或許氫燃料電池會先從軍事用途發展也說不定。

(首圖來源:) 

(本文授權轉載自《》─〈〉)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

Gogoro 將不再受限充電站,GoCharger 讓騎士在家在商店都可充

曾在 2015 年 CES 展中展出新一代電動車的 Gogoro 於 2016 年再度參加美國 CES 消費電子大展,除了分享 Smartscooter 智慧雙輪的佈建經驗、展示全新智慧功能外,並發表了 GoCharger 智慧電池座,讓個人或商店也可以提供設置充電座,讓 Gogoro 不再受限於現有的充電站,擴大 Gogoro 的行駛區域。

Gogoro 執行長暨共同創辦人陸學森表示:「自從上市以來我們持續聆聽消費者的聲音,並在去(2015)年七月承諾開發個人充電設備,很高興在此向大家正式介紹 GoCharger 智慧電池座。在不久的將來,車主可以到餐廳或商店,一面用餐購物、一面使用 GoCharger 智慧電池座為 Gogoro 電池充電,讓人車都獲得能源補給再前往下一個目的地。」

GoCharger 輕鬆設置在家中或商店內,只要將兩顆 Gogoro 電池置入電池槽,電池座即會透過無線網路連結 Gogoro 能源網路雲端系統進行電池認證,除了車主可以透過 Gogoro App 頁面查看充電狀況之外,Gogoro 亦可於遠端進行電量管理、控制充電速度與觀察電池健康狀態。GoCharger 智慧電池座將提供「快充」與「標準」兩個版本,預計最快將於 2016 年下半年正式上市。

陸學森也進一步表示,「為讓更多城市有機會參與 Gogoro 能源網路的推廣計畫,我們也宣布正式啟動 Gogoro OPEN 共享計劃,邀請全球消費者與商家上網申請設置 GoCharger 智慧電池座,反應最熱烈的地方就有可能成為 Gogoro 進駐的下一個城市。」

結合手機即可無鑰上鎖開啟車廂   除分享 GoCharger 智慧電池座與 Gogoro OPEN 能源網路共享計劃外,執行長陸學森也表示智慧型手機已成為消費者生活中不可或缺的工具,因此 Gogoro也希望結合更多手機應用、持續優化車主的騎乘體驗,因為推出了最新的智慧解鎖功能,只要透過智慧型手機(iOS/Android)或是 Apple Watch ,車主不需鑰匙即可上鎖、解鎖智慧雙輪與開啟後車廂。

  這個新功能未來會預先安裝於接下來新型式年份的 Gogoro 電動機車上,而 Gogoro 也將為所有車主提供免費軟硬體升級,並於近期公佈車主回廠進行更新的流程,該原有的車主也可以體驗到此一功能。  
2015 年 12 月份銷售翻倍,台北市佔率達 10.8%   發表新功能之外,Gogoro 也公布了相關銷售成績,目前雖然僅於大台北、桃園與新竹地區販售,在 12 月整體機車市場僅微幅成長 2% 的情況下,Gogoro 創造銷售成長 210% 、掛牌數達到 1,528 台,除穩坐電動機車市場龍頭寶座,更較第二名全國掛牌總數多出近 900 輛。   在上述區域的商用和自用電動機車市場中,每四台新車就有三台是 Smartscooter 智慧雙輪,若單看自用市場則是十台新車有超過九台是智慧雙輪,佔比高達 91%,數據顯示 Gogoro 在上一波的售價調整下已達到成效,大幅提升消費者的接受度。   目前在雙北與桃竹地區,Gogoro 於機車整體市場佔有率為 8.3%,台北市更是首度超過一成達到市佔率 10.8% 的成績。現今全台已有近四千台的智慧雙輪在道路上奔馳,接下來除配合便利商店與其他地區的擴展外,再加上新的 GoCharger 不再受限於現有充電站下與以及 Gogoro OPEN 的計劃執行,應可再拉升原本還在猶豫的消費者選擇。   (本文授權轉載自《》─〈〉)  

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享